Skip to content

fix: use correct target folder for createFolder/uploadFile in Workspace fs#1913

Merged
misha-db merged 5 commits into
mainfrom
wsfs-fix-root-folder-creation
Jun 18, 2026
Merged

fix: use correct target folder for createFolder/uploadFile in Workspace fs#1913
misha-db merged 5 commits into
mainfrom
wsfs-fix-root-folder-creation

Conversation

@misha-db

@misha-db misha-db commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Changes

Fixes title bar click after deselection was targeting the previously selected folder instead of root.

extension.ts

Switches the Workspace FS panel registration from window.registerTreeDataProvider to window.createTreeView so the TreeView handle (which exposes selection) is available. The resulting workspaceFsTreeView is passed to WorkspaceFsCommands and disposed via context.subscriptions.

WorkspaceFsCommands.ts

  • Accepts TreeView as a new constructor parameter (private readonly treeView).
  • Tracks the last left-click–selected item in selectedElement via treeView.onDidChangeSelection (cleared to undefined on deselection).
  • In createFolder and uploadFile, resolves the target folder using a comparison:
    • If element !== treeView.selection[0] — the command was invoked from a context menu on a different item than the current selection → use element.
    • Otherwise — title bar button, or context menu on the already-selected item → use selectedElement (which is undefined if the user deselected before clicking, correctly falling back to the workspace root).

Tests

WorkspaceFsCommands.test.ts

…ce FS

extension.ts

Switches the Workspace FS panel registration from window.registerTreeDataProvider to window.createTreeView so the
TreeView handle (which exposes selection) is available. The resulting workspaceFsTreeView is passed to
WorkspaceFsCommands and disposed via context.subscriptions.

WorkspaceFsCommands.ts

- Accepts TreeView<WorkspaceFsEntity> as a new constructor parameter (private readonly treeView).
- Tracks the last left-click–selected item in selectedElement via treeView.onDidChangeSelection (cleared to
undefined on deselection).
- In createFolder and uploadFile, resolves the target folder using a comparison:
  - If element !== treeView.selection[0] — the command was invoked from a context menu on a different item than the
current selection → use element.
  - Otherwise — title bar button, or context menu on the already-selected item → use selectedElement (which is
undefined if the user deselected before clicking, correctly falling back to the workspace root).

This fixes two bugs:
1. Title bar click after deselection was targeting the previously selected folder instead of root.
2. Context-menu click on a non-selected item was targeting the selected folder instead of the right-clicked one.
@misha-db misha-db requested a review from anton-107 June 16, 2026 15:59
@misha-db misha-db temporarily deployed to test-trigger-is June 16, 2026 15:59 — with GitHub Actions Inactive
@misha-db misha-db requested a review from rugpanov June 16, 2026 16:00
@misha-db misha-db temporarily deployed to test-trigger-is June 16, 2026 16:13 — with GitHub Actions Inactive
@anton-107

Copy link
Copy Markdown
Contributor

Concern: this may not actually fix the reported bug (and the tests don't guard against it)

I traced the logic and I think the core change is effectively a no-op. The key helper:

private resolveTargetElement(element?) {
    return element !== this.treeView.selection[0]
        ? element
        : this.selectedElement;
}

selectedElement is maintained by the listener as this.selectedElement = e.selection[0], so it stays in sync with treeView.selection[0]. At command-invocation time selectedElement === treeView.selection[0]. Substituting that invariant into both branches:

  • element !== selection[0] → returns element
  • element === selection[0] → returns selectedElement (=== selection[0] === element) → also element

So resolveTargetElement(element) reduces to element in every case. The PR swaps element?.path for resolveTargetElement(element)?.path, which yields the same value — behaviorally unchanged.

The tests pass against the original code too. I ran all 13 cases against the pre-PR logic (rootPath = element?.path ?? root, plus the uploadFile DIRECTORY/REPO variant) and every assertion holds — createFolder(entityA)entityA.path, createFolder(undefined) → root, uploadFile(fileEntity) (type FILE) → root, etc. A regression test meant to lock in this fix should fail on the old code; none of these do, so they're validating existing behavior rather than the fix.

Why I don't think the reported bug is addressed. The "title bar after deselection targets the previously selected folder" bug can only occur if, at title-bar-click time, the element/selection VSCode hands the command still points at the stale folder. But in that exact state element === treeView.selection[0] (both stale) and selectedElement tracks the same value — so the new code returns the same stale folder. The deselection test sidesteps this by modeling deselection as simulateSelect(undefined) (everything cleared → root), which is the non-buggy state, rather than reproducing the actual repro.

Possible regression risk. The logic also relies on the assumption (stated in a test comment) that a right-click does not update treeView.selection. If in the running VSCode version a context-menu right-click does update the selection before selectedElement catches up, then "right-click B while A is selected" takes the === branch and returns selectedElement (A) instead of B — creating the folder under the wrong item.

Suggestion: before merging, could you verify the deselection repro empirically with vs. without this diff? If there's a real difference, it'd be worth pinning down exactly what VSCode passes for title-bar vs. context-menu invocations and adding a test that fails on the old code to prove the fix matters. If the intent is "title bar always creates at root, context menu uses the clicked item," distinguishing the two invocation paths explicitly (separate command IDs/args) would be more robust than reconciling element against tracked selection.

When the toolbar button is clicked, VS Code
passes the currently-selected tree node as `element`, making it
impossible to distinguish toolbar vs context-menu invocations from a
single handler.

Changes:
- Add `databricks.wsfs.uploadFile.toolbar` command bound to `view/title`;
  the existing `databricks.wsfs.uploadFile` stays on `view/item/context` only.
- Both handlers resolve the target folder directly from `element` (toolbar
  variant via `resolveTargetElementForToolbar`, which gates on
  `treeView.selection` to detect whether anything is truly selected).
- Extract shared upload logic into private `doUploadFile`.
- Remove the now-unused `resolveTargetElement` helper.
- Update unit tests: rename mislabelled "title bar" cases, add dedicated
  suites for `createFolderFromToolbar` and `uploadFileFromToolbar` covering
  the full selection-state matrix.
@misha-db

Copy link
Copy Markdown
Contributor Author

Handling 2 issues in last commit

  1. vscode treeview api doesn't provide tree node deselection events. provides stale selected node. causing bug when
    selecting folder -> deselecting folder -> clicking create folder. instead of created folder under root (as nothing is selected currently) created it under originally selected folder

  2. there is no way to differentiate between calling handler from context menu vs toolbar (same handler).
    causing bug when user selects one folder, but then right clicks another folder (selection stay on original one) and invokes create folder, it created under selected folder instead of right clicked node.

Separately toolbar and context versions of createFolder and uploadFolder commands.

2 new command IDs
"databricks.wsfs.createFolder.toolbar",
"databricks.wsfs.uploadFile.toolbar",

@anton-107 anton-107 left a comment

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.

Approving — the redesign addresses my earlier concern directly. Splitting into separate view/title (toolbar) and view/item/context (context-menu) command IDs is the explicit-invocation-path approach I was hoping for: the old resolveTargetElement no-op is gone, the context menu now uses the right-clicked element directly (so right-click B while A is selected correctly targets B — my regression worry), and the toolbar gates on live treeView.selection to ignore the stale element after deselection. 👍

Two minor, non-blocking notes you can pick up whenever (or not):

  1. Verify the repro empirically. The unit tests are good, but they exercise a FakeTreeView that encodes the assumed VS Code contract (stale element arg vs. accurate treeView.selection, and view/title passing the selected node). They can't prove the real VS Code behavior. If you've already run the actual select → deselect → click-toolbar repro against this build and confirmed it now lands at root, a quick note here would fully close the loop for me.

  2. Toolbar resolver could read selection directly. When treeView.selection[0] is defined, resolveTargetElementForToolbar returns the passed element rather than this.treeView.selection[0]. They should be equal in the toolbar path, but returning treeView.selection[0] directly would be self-evidently correct without depending on element === selection[0].

@github-actions

Copy link
Copy Markdown
Contributor

If integration tests don't run automatically, an authorized user can run them manually by following the instructions below:

Trigger:
go/deco-tests-run/vscode

Inputs:

  • PR number: 1913
  • Commit SHA: e8d52241dd0ceb704c8beb4671819c29704b7f4f

Checks will be approved automatically on success.

@misha-db misha-db merged commit be427e9 into main Jun 18, 2026
6 of 8 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 18, 2026
misha-db pushed a commit that referenced this pull request Jun 18, 2026
## packages/databricks-vscode
##  (2026-06-18)

* fix: use correct target folder for createFolder/uploadFile in
Workspace fs (#1913)
([be427e9](be427e9)),
closes
[#1913](#1913)
* Drop the “or greater” addition on the line where extension suggests to
activate a Python environment
([13452fb](13452fb)),
closes
[#1915](#1915)
* Gate WSFS and docs panels on extension activation (#1909)
([308f687](308f687)),
closes
[#1909](#1909)
* Pass DATABRICKS_CLI_PATH and resolve the platform-specific CLI binary
(#1910)
([6fcb630](6fcb630)),
closes
[#1910](#1910)
[#1903](#1903)



## packages/databricks-vscode-types
##  (2026-06-18)

Co-authored-by: releasebot <noreply@github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants