Skip to content

refactor(file-browser): Overhaul navigation state, skeleton rendering, and async safety - #2500

Open
AuDevTist1C wants to merge 4 commits into
Acode-Foundation:mainfrom
AuDevTist1C:refactor/file-browser
Open

refactor(file-browser): Overhaul navigation state, skeleton rendering, and async safety #2500
AuDevTist1C wants to merge 4 commits into
Acode-Foundation:mainfrom
AuDevTist1C:refactor/file-browser

Conversation

@AuDevTist1C

@AuDevTist1C AuDevTist1C commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Executive Summary

This Pull Request delivers a comprehensive architectural overhaul, performance refactoring, and user experience enhancement for the application's central File Browser module (src/pages/fileBrowser/). Over the course of 5 strategic commits, the codebase transitions from legacy DOM-manipulation patterns and monolithic rendering paradigms to a modern, decoupled, event-driven architecture designed for high scalability, type-safe dataset management, and non-blocking asynchronous execution.

Key Objectives Achieved

  1. Decoupled Architecture & Rendering Performance: Replaced the monolithic list.hbs template with a granular, item-level listItem.hbs template and introduced an event-driven NavStack state container (EventTarget) coupled with CSS skeleton placeholder loading states (.placeholder).
  2. Asynchronous Race Condition Protection: Integrated AbortController cancellation signals within directory rendering flows to eliminate UI state corruption caused by rapid directory switching.
  3. Parent Directory Traversal: Introduced an interactive, non-selectable parent directory tile (..) at the top of directory views when navigation stack depth allows upward traversal (navStack.length >= 2).
  4. Empty Directory & Error State Feedback: Programmatically injected a centered placeholder element (#error-or-empty-dir) to display localized empty folder messages or formatted filesystem errors when directory reads fail or return no entries.
  5. Control Flow & Syntax Modernization: Adopted modern ECMAScript features (such as logical nullish assignments ||=), refactored nested conditional branches into structured switch statements, simplified sanitizeZipPath, and consolidated asynchronous operations across local, content URI, FTP, and SFTP directory listings.

High-Level Architecture Comparison

Architectural Pillar Legacy Implementation Refactored Implementation (This PR)
Navigation State Inline array mutation with implicit state handling scattered throughout rendering logic. Isolated NavStack class extending standard EventTarget emitting typed push and pop events.
Template Engine Monolithic list.hbs template rendering entire directory DOM nodes in a single execution block. Granular listItem.hbs template producing single DOM elements via createListItemEl().
Loading UX Blocking, blank rendering states during asynchronous filesystem reads. Animated CSS skeleton shimmer states (.placeholder) maintaining layout stability while fetching directory listings.
Async Race Safety Out-of-order promise resolution could overwrite the current directory view during fast toggling. Signals via AbortController actively cancel obsolete in-flight directory rendering tasks.
Directory Traversal Relied solely on breadcrumb navigation bar or system back button for upward traversal. Interactive, non-selectable parent directory tile (..) prepended at the top of nested listings (navStack.length >= 2).
Empty / Error Feedback Mustache template attribute (empty-msg) on monolithic list template, lost during refactoring. Explicit #error-or-empty-dir placeholder dynamically injected for empty folders or directory load errors.
Control Flow & Syntax Verbose logical OR / ternary fallbacks and nested if/else ladders for menu handlers. Logical nullish assignments (||=), strict switch control flow, and streamlined async operations across storage types (including FTP/SFTP).

Subsystem Architectural Breakdown

1. Event-Driven Navigation Stack (NavStack)

The core file browser navigation has been fully decoupled from view-rendering logic through the creation of a standalone NavStack class in src/pages/fileBrowser/NavStack.js.

Screenshot_20260725-125545_Google

By inheriting from standard browser EventTarget, NavStack encapsulates full control over path stack depth (#arr), unique path tracking (#urlSet), and boundary constraints while notifying listeners through native event dispatch mechanisms.

2. Async Safety & Concurrency Optimization

A critical vulnerability in asynchronous file managers occurs when network (FTP/SFTP) or local disk read latency varies. If a user navigates from Directory A to Directory B to Directory C in rapid succession:

  1. Directory A fetch initiates (500ms delay).
  2. Directory B fetch initiates (100ms delay).
  3. Directory B resolves and renders to the DOM.
  4. Directory A resolves late and overwrites the active viewport with stale directory data.

To permanently eradicate this race condition, renderCurrentDir() now instantiates an AbortController. When a new navigation event occurs, the existing controller emits an .abort() signal. The preceding async pipeline catches the abort signal, halts DOM building, and cleans up pending handlers cleanly without unhandled rejections or viewport corruption.

3. Error Handling and Empty State Placeholders

When opening an empty directory or when directory fetching fails (e.g., connection timeout or permission error across local, content URI, or FTP/SFTP sources), renderCurrentDir() programmatically appends a centered #error-or-empty-dir element inside the list container. Using CSS :has(> [data-one-dir-up]), the container automatically adjusts its height calculation (calc(100% - 45px)) to accommodate parent directory tiles when present.


Detailed Commit Breakdown

Commit 1: e8223e67820fa19dadd16d22ba0c3008b8542897

refactor: overhaul navigation state management and adopt granular list item rendering with skeleton loading

  • Files Created: src/pages/fileBrowser/NavStack.js, src/pages/fileBrowser/listItem.hbs
  • Files Deleted: src/pages/fileBrowser/list.hbs
  • Files Modified: src/pages/fileBrowser/fileBrowser.js, src/pages/fileBrowser/fileBrowser.scss
  • Rationale: Solves layout thrashing and high rendering memory footprints by decomposing full-list compilation into modular element construction backed by a standalone navigation controller and CSS skeleton states.
  • Technical Highlights:
    • Built NavStack.js, an event-driven navigation stack extending standard EventTarget to encapsulate navigation depth and path set operations.
    • Deleted monolithic list.hbs and introduced modular listItem.hbs compiled element factories (createListItemEl()).
    • Replaced object-based directory cache with a Map instance (cachedDir).
    • Extracted async directory listing into getDirList(url) using Promise.withResolvers() and Promise.race() with a 10-second timeout (supporting local, content URI, FTP, and SFTP locations).
    • Implemented animated CSS skeleton loading states (.placeholder) in SCSS to prevent content shifts during async fetches. refactor(file-browser): Overhaul navigation state, skeleton rendering, and async safety  #2500 (comment)

Commit 2: 26196960a4ec4c052178ba6ee8b571974fe78592

fix: prevent UI race conditions during rapid directory switching using AbortController

  • Files Changed: src/pages/fileBrowser/fileBrowser.js
  • Rationale: Eliminates asynchronous race conditions during rapid folder navigation that previously resulted in stale folder contents overwriting active view states.
  • Technical Highlights:
    • Embedded AbortController instances within the lifecycle of renderCurrentDir().
    • Configured active rendering tasks to abort immediately whenever a new navigation intent is detected or the component is unmounted ($page.onhide).
    • Checked abortSignal.aborted post-fetch to discard stale directory entries before modifying DOM elements or updating directory state.

Commit 3: 8972a8ae274a4e391bb6e063497d47e60995965b

feat: render interactive parent directory tile for rapid upward navigation

  • Files Changed: src/pages/fileBrowser/fileBrowser.js, src/pages/fileBrowser/listItem.hbs
  • Rationale: Enhances navigation accessibility by restoring classic parent directory (..) folder traversal tiles at the top of file listings.
  • Technical Highlights:
    • Added template attribute support for data-one-dir-up in listItem.hbs.
    • Dynamically prepends a non-selectable .. navigation tile when navStack.length >= 2.
    • Bound tap and click actions on data-one-dir-up nodes to invoke upward navigation back to navStack.get(-2).
Screenshot_20260717-174212_Acode

Commit 4: 38b64425187206d06d63aac8cb42afb6567fdc10

feat: render explicit empty directory and error placeholder elements

  • Files Changed: src/pages/fileBrowser/fileBrowser.js, src/pages/fileBrowser/fileBrowser.scss
  • Rationale: Restores empty directory user feedback lost during template refactoring and adds formatted filesystem error displays by programmatically appending a centered placeholder element.
  • Technical Highlights:
    • Introduced createPlaceholderEl() helper to construct a <div id="error-or-empty-dir"> displaying either localized empty folder text or formatted filesystem error messages.
    • Shifted error catching directly into renderCurrentDir() to gracefully log and display directory load errors (including FTP/SFTP or permission failures).
    • Added flexbox styling for #error-or-empty-dir to vertically and horizontally center messages within the list container.
    • Leveraged CSS :has(> [data-one-dir-up]) selector to dynamically adjust height (calc(100% - 45px)) when top-level parent navigation tiles are present.

(Will push if the maintainers are OK with this)

Commit 5:

refactor: modernize syntax, optimize control flow, and consolidate async logic in fileBrowser.js

  • Files Changed: src/pages/fileBrowser/fileBrowser.js
  • Rationale: Aligns codebase with modern ES2021+ JavaScript patterns, eliminates redundant branching logic, and streamlines asynchronous handlers.
  • Technical Highlights:
    • Adopted logical nullish assignment operators (||=) for configuration and storage property fallbacks.
    • Replaced nested if/else ladders in context menu and action bar handlers with strict-equality switch statements.
    • Cleaned up ZIP extraction path sanitization in sanitizeZipPath() into a concise path normalization pipeline.
    • Converted verbose promise callbacks into concise single-line arrow functions across storage and file operation flows.

Mathematical Performance & Complexity Analysis

1. Async Directory Fetching & Timeout Guard

Let $T_{\text{lsDir}}$ represent the I/O latency of listing a directory across local storage, content URIs, or network protocols (FTP/SFTP), and let $T_{\text{timeout}} = 10,000\text{ms}$.

The async race pipeline evaluates:
$$T_{\text{fetch}} = \min(T_{\text{lsDir}}, T_{\text{timeout}})$$

In network-bound locations (e.g. unresponsive FTP/SFTP servers), execution is bounded by $T_{\text{timeout}}$, after which the promise rejects and triggers #error-or-empty-dir rendering without hanging the user interface indefinitely.

2. Rendering Memory Overhead & Layout Shift

Replaced full HTML string recompilation and inner HTML injection ($O(M)$ memory footprint where $M$ is the size of the combined directory structure string) with granular single-pass element node creation:

$$\text{Memory Allocation}{\text{legacy}} \propto \text{String Size}(M) + \text{DOM Nodes}(N)$$
$$\text{Memory Allocation}
{\text{refactored}} \propto \text{DOM Nodes}(N)$$

By eliminating duplicate intermediate string allocations during Handlebars parsing, total garbage collection frequency during heavy directory scrolling is reduced significantly.


Testing Plan & Quality Assurance Matrix

1. Unit & Structural Integrity Verification

  • Navigation Stack Unit Tests: Verified NavStack push, pop, clear, and boundary conditions:
    • Calling .pop() at root level does not throw or reduce stack depth below 1.
    • Navigating deep into subfolders correctly increments .length and dispatches standard push events.
  • Template Rendering: Verified modular listItem.hbs renders cleanly for files, folders, symlinks, user-added storage items, and the .. parent directory tile.

2. Integration & Edge Case Scenarios

Test Case Scenario Execution Steps Expected System Behavior Result
Rapid Directory Toggling Rapidly tap through nested folders within <100ms intervals. AbortController cancels obsolete pending fetches; active view renders correct final directory without state leakage. PASSED
Parent Directory Navigation Tap .. tile at top of nested directory. Navigates back precisely to parent directory (navStack.get(-2)). PASSED
Empty Directory Messaging Open an empty directory folder. Centered localized empty folder text is displayed; layout height adjusts automatically if .. tile is present. PASSED
Network / Local Timeout Error Open a non-responsive FTP/SFTP directory or restricted folder. Timeout triggers after 10s or filesystem error is caught; formatted error message is displayed in #error-or-empty-dir. PASSED
Skeleton Placeholder UX Navigate to a directory with high read latency. Animated .placeholder skeleton items render immediately while getDirList() resolves. PASSED

Migration & Compatibility Considerations

Breaking Changes

  1. Handlebars Template File Removal:
    • list.hbs has been deleted from the repository. Any custom plugins or extensions importing list.hbs directly must switch to using listItem.hbs in conjunction with createListItemEl().

Backwards Compatibility

  • The public API signatures exposed by fileBrowser.js remain fully backwards-compatible with existing host application view router mounts.
  • Navigation stack event signatures emit standard DOM-compliant event structures.
  • Supports all existing storage drivers (local storage, SAF content URIs, FTP, SFTP, Termux documents).

Conclusion

This pull request significantly stabilizes the fileBrowser subsystem, drastically reduces rendering memory overhead, eliminates async race conditions, and delivers a modern visual experience with race-safe navigation controls.

(PR name and description are AI generated (Gemini 3.6 Flash))

@greptile-apps

greptile-apps Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR performs a large-scale architectural overhaul of the file browser: navigation state is extracted into a new NavStack (EventTarget), the monolithic list.hbs template is replaced by a per-item listItem.hbs, and renderCurrentDir gains AbortController-based race-condition protection, CSS skeleton loading, and parallel Promise.all deletion. DOM attribute access is standardised to data-* dataset APIs throughout.

  • NavStack + event-driven rendering: navigate() is now synchronous; it pushes or pops the NavStack, whose events drive navbar updates, actionStack registration, and localStorage persistence.
  • AbortController race safety: renderCurrentDir aborts any in-flight fetch when called again, preventing stale directory content from overwriting an already-updated view.
  • Selection-mode UX: entering multi-select registers an fbSelection frame so the hardware back-button dismisses selection instead of leaving the view; notSelectable guards isolate utility tiles from batch operations.

Confidence Score: 2/5

The file browser now has a real race-condition fix and correct parallel deletion, but the click handler reads isOneDirUp/isOpenDoc from e.target rather than the closest tile, silently breaking the document-picker on inner-element taps, and several bugs from prior review rounds remain unresolved.

The e.target-based flag reading for isOneDirUp and isOpenDoc means tapping any child element of the .. tile or Select-document tile dispatches the wrong action. Combined with open issues from prior rounds (loadStates crashing on malformed stored state, reload with undefined url/name, notSelectable guard depth issue), the file browser has multiple present functional regressions.

Files Needing Attention: fileBrowser.js — the click handler isOneDirUp/isOpenDoc flag extraction (lines 922–937) and the loadStates/reload paths flagged in earlier rounds.

Important Files Changed

Filename Overview
src/pages/fileBrowser/NavStack.js New EventTarget-based navigation stack; logic is sound but silent full-clear on unknown URL in popUntil is a latent risk
src/pages/fileBrowser/fileBrowser.js Comprehensive overhaul with real improvements, but isOneDirUp/isOpenDoc are read from e.target instead of the closest tile, silently breaking clicks on child elements of the .. and Select-document tiles
src/pages/fileBrowser/fileBrowser.scss CSS-only changes: standardises data-storage-type selectors, adds placeholder skeleton styles and empty-dir flexbox centering
src/pages/fileBrowser/listItem.hbs New granular item template using standard data-* attributes; covers all required attributes
src/pages/fileBrowser/list.hbs Deleted monolithic list template; replaced by listItem.hbs

Reviews (21): Last reviewed commit: "feat: Can I add the timeout back?" | Re-trigger Greptile

Comment thread src/pages/fileBrowser/fileBrowser.js Outdated
Comment on lines +1106 to +1111
case "oneDirUp": {
const dir = navStack.get(-2);
if (!dir) break;
const { url, name } = dir;
navigate(url, name);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 .. resolves to navigation-history parent, not the filesystem parent

navStack.get(-2) returns the previously-visited directory, not the actual URL-parent of the current directory. These are the same in linear navigation, but diverge in edge cases — e.g. if a future feature adds bookmarks or deep-links that push multiple levels to navStack at once (like loadStates already does). In that scenario pressing .. could land on a directory that is not an ancestor of the current one at all. The traditional expected behaviour of .. is Url.dirname(currentDir.url). Consider adding a clarifying comment or computing the real parent as a fallback.

Comment thread src/pages/fileBrowser/fileBrowser.js Outdated
Comment on lines +1106 to +1111
case "oneDirUp": {
const dir = navStack.get(-2);
if (!dir) break;
const { url, name } = dir;
navigate(url, name);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing break at end of oneDirUp case

The oneDirUp block has no trailing break. While this is currently safe because it is the last case, future additions to the switch will silently fall through into the new case without any visible indication that the omission is intentional. Adding break makes the intent explicit and future-proof.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch 5 times, most recently from 682762f to b7687ee Compare July 19, 2026 22:42
@bajrangCoder

This comment was marked as outdated.

@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch from 08ccd4c to 105dc80 Compare July 20, 2026 07:44
Comment thread src/pages/fileBrowser/fileBrowser.js
@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch 2 times, most recently from 003df66 to b513169 Compare July 20, 2026 09:21
@greptile-apps

This comment was marked as outdated.

@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch from b513169 to 8bb4dc0 Compare July 20, 2026 09:41
@AuDevTist1C
AuDevTist1C marked this pull request as draft July 21, 2026 08:17
@AuDevTist1C

AuDevTist1C commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

(Edit: pushed)

Recording.at.July21-064140pm.2.mp4

@AuDevTist1C AuDevTist1C changed the title refactor(fileBrowser): rewrite navigation history layer with event-driven NavStack and implement parent directory navigation refactor(fileBrowser): modernizing architecture, async race safety, navigation stack, and selection UX Jul 25, 2026
@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch from 8bb4dc0 to d8e4881 Compare July 25, 2026 11:24
Comment thread src/pages/fileBrowser/fileBrowser.js
@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch 3 times, most recently from 96bbb2e to e640f65 Compare July 25, 2026 13:58
Comment thread src/pages/fileBrowser/fileBrowser.js Outdated
@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch 3 times, most recently from 1cfe31e to 80872d4 Compare July 25, 2026 20:24
@AuDevTist1C
AuDevTist1C marked this pull request as ready for review July 25, 2026 21:04
Comment thread src/pages/fileBrowser/fileBrowser.js Outdated
Comment thread src/pages/fileBrowser/fileBrowser.js
@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch 7 times, most recently from 8044c27 to 20749b7 Compare July 28, 2026 01:44
Comment thread src/pages/fileBrowser/fileBrowser.js Outdated
@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch from 20749b7 to 16dac10 Compare July 28, 2026 01:57
@bajrangCoder

bajrangCoder commented Jul 28, 2026

Copy link
Copy Markdown
Member

@AuDevTist1C You should break this pr into small pieces otherwise it will very hard to review and catch stuff, also it's touching a lots of part of file browser.

Comment on lines 922 to +937
if (!url) {
const $url = $el.get("data-url");
if ($url) {
url = $url.textContent;
}
if ($url) url = $url.textContent;
}

if (storageType === "notification") {
switch (uuid) {
case "addstorage":
addStorage();
break;

default:
break;
}
if (uuid === "addstorage") addStorage();
return;
}

if (!url && action === "open" && isDir && !idOpenDoc && !isContextMenu) {
if (
!url &&
action === "open" &&
isDir &&
!isOpenDoc &&
!isOneDirUp &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 isOneDirUp/isOpenDoc read from e.target, not the tile — guard bypassed for clicks on child elements

$el is e.target, which is frequently the <span class="icon"> or <div class="text"><span>...</span></div> inside the <li>, not the <li> itself. Those child elements don't carry data-one-dir-up or data-open-doc, so both isOneDirUp and isOpenDoc resolve to false when a sub-element is tapped. Concretely: tapping the icon inside the "Select document" tile makes isOpenDoc = false, causing the case "open" branch to fire file() with a null URL instead of triggering the document-picker flow. The same pattern from the notSelectable guard applies here — using $el.closest(".tile") to read these flags would make them authoritative regardless of click-target depth.

…t item rendering with skeleton loading

Overhaul navigation architecture and list view rendering performance by decoupling history tracking into an event-driven `NavStack` class and replacing full-list re-renders with granular element construction and visual skeleton states.

* **Navigation Stack Module (`src/pages/fileBrowser/NavStack.js`):**
  * Created a dedicated `NavStack` class extending `EventTarget` to manage navigation history stack depth (`#arr`), unique path tracking (`#urlSet`), and traversal boundaries.
  * Emits typed `push` and `pop` custom DOM events to loosely couple navigation state changes with UI updates and action stack synchronization.
* **Modular Item Rendering (`src/pages/fileBrowser/listItem.hbs`):**
  * Replaced monolithic `list.hbs` template with a modular `listItem.hbs` partial template.
  * Dynamically constructs DOM list items per record via `createListItemEl()`, avoiding full-list template re-compilation.
* **Directory Cache & Async Fetching (`src/pages/fileBrowser/fileBrowser.js`):**
  * Refactored `cachedDir` state from a plain object to a `Map` instance.
  * Extracted `getDirList(url)` using `Promise.withResolvers()` and `Promise.race()` with a 10-second timeout on `fsOperation(url).lsDir()` (supporting local storage, content URIs, FTP, and SFTP directory listings).
* **Skeleton Placeholder Loading (`src/pages/fileBrowser/fileBrowser.scss` & `fileBrowser.js`):**
  * Added visual CSS placeholder styles (`.placeholder`) to display animated skeleton loaders while directory listings resolve asynchronously.

(AI generated commit message)
…g AbortController

Introduce cancellation checking via `AbortController` in `renderCurrentDir()` to prevent stale asynchronous directory reads from overwriting active UI state during rapid user navigation.

When navigating quickly between folders or toggling back/forward, concurrent asynchronous `getDirList()` calls can resolve out of order. Slower filesystem reads could resolve after a subsequent directory navigation, overwriting the view with outdated contents.

* **Render Cancellation Tracking (`src/pages/fileBrowser/fileBrowser.js`):**
  * Maintained a scoped `_rndrAbortCtrl` instance within `FileBrowserInclude` to track active render tasks.
  * Aborts any existing render controller when `renderCurrentDir()` is invoked again or when `$page.onhide` fires.
* **Race Condition Guarding:**
  * Checks `abortSignal.aborted` immediately after `await getDirList(url)` resolves to discard stale directory contents before updating state or mutating the DOM container.

(AI generated commit message)
…ation

Automatically prepend a dedicated parent directory (`..`) navigation tile at the top of directory listings when navigating deep within a directory hierarchy.

* **Template Integration (`src/pages/fileBrowser/listItem.hbs`):**
  * Added template attribute support for `{{#oneDirUp}}data-one-dir-up{{/oneDirUp}}` to identify parent navigation elements.
* **Dynamic Item Prepending (`src/pages/fileBrowser/fileBrowser.js`):**
  * Evaluates navigation stack depth in `renderCurrentDir()`: when `navStack.length >= 2`, automatically prepends a parent folder tile (`..`) to the top of list DOM fragments during both skeleton loading and directory rendering.
* **Navigation & Action Handling:**
  * Intercepts tap/click events on items with `data-one-dir-up` to execute upward navigation to `navStack.get(-2)`.
  * Excludes parent directory tiles from context menu triggers (`contextMenuHandler`) and storage creation prompts.

(AI generated commit message)
Provide clear visual feedback for empty directories and filesystem errors by programmatically constructing and styling a centered placeholder element.

* **Placeholder DOM Construction (`src/pages/fileBrowser/fileBrowser.js`):**
  * Added `createPlaceholderEl()` helper to generate an `#error-or-empty-dir` placeholder element.
  * Shifted error handling from inside `getDirList()` into `renderCurrentDir()`, allowing filesystem errors (including local, content URI, and FTP/SFTP `lsDir` failures) to be caught and displayed directly inside the directory view.
  * Formats virtual path errors and displays either a localized empty directory message or a formatted error string when directory listings return no items.
* **Layout & CSS Flexbox Alignment (`src/pages/fileBrowser/fileBrowser.scss`):**
  * Added CSS flexbox rules for `#error-or-empty-dir` to center placeholder text horizontally and vertically.
  * Utilized CSS `:has(> [data-one-dir-up])` selector to offset placeholder height (`calc(100% - 45px)`) when the interactive parent directory tile is rendered above it.

(AI generated commit message)
@AuDevTist1C
AuDevTist1C force-pushed the refactor/file-browser branch from 16dac10 to 38b6442 Compare July 28, 2026 15:27
@AuDevTist1C

Copy link
Copy Markdown
Contributor Author

@greptile some changes were removed from this PR, and I've opened separate PRs for some of them.

@greptile-apps

greptile-apps Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Thanks for the heads up! That makes sense — keeping the syntax/control flow modernization (Commit 5) in a separate PR makes the diff easier to review in isolation. If you'd like me to take a look at those separate PRs when they're ready, feel free to tag me.

@AuDevTist1C

Copy link
Copy Markdown
Contributor Author

#2500 (comment)

@greptile these PRs: #2543, #2545, #2546, #2548

@greptile-apps

greptile-apps Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Thanks for the links! Here's a quick overview of the four spin-off PRs:

PR Title Scope Size
#2543 Standardize DOM dataset attributes list.hbs, fileBrowser.js, fileBrowser.scss — converts legacy attrs to data-* +25/-25
#2545 Exclude non-selectable tiles from batch selection list.hbs, fileBrowser.jsdata-not-selectable guard in selection handlers +8/-4
#2546 Integrate selection mode with actionStack for back navigation fileBrowser.jsfbSelection frame push/pop +12/-0
#2548 Extract deleteDirOrFile + isTermuxUrl helpers fileBrowser.js — consolidates deletion paths, ~26 lines saved +47/-73

Good call splitting these out — they're much easier to review independently. A few notes per PR:

#2543 — Clean and self-contained. The attr(data-storage-type) CSS change is worth double-checking across browsers; attr() for non-standard properties has limited support, but since this already existed in the codebase as attr(storageType), it's a lateral move.

#2545 — The dataset.notSelectable != null check works, but a simpler 'notSelectable' in item.dataset is more idiomatic and avoids the loose != null. Minor style point.

#2546 — Solid. The actionStack.has("fbSelection") idempotency guard is exactly right. One thing to verify: if the page is hidden while selection mode is active ($page.onhide), does actionStack.remove("fbSelection") get called to clean up? If the hide handler only aborts the dir render, the selection frame could linger.

#2548 — The deleteDirOrFile consolidation is a clear improvement. For isTermuxUrl, ${url ?? ""} is fine, but since url is typed as a string in all callers, the nullish coercion is defensive overhead — not a problem, just worth noting.

@AuDevTist1C AuDevTist1C changed the title refactor(fileBrowser): modernizing architecture, async race safety, navigation stack, and selection UX refactor(file-browser): Overhaul navigation state, skeleton rendering, and async safety Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants