Skip to content

Add create file support to WSFS explorer#1922

Open
misha-db wants to merge 3 commits into
mainfrom
wsfs-add-file
Open

Add create file support to WSFS explorer#1922
misha-db wants to merge 3 commits into
mainfrom
wsfs-add-file

Conversation

@misha-db

Copy link
Copy Markdown
Contributor

Changes

Adds the ability to create new files directly in the Databricks Workspace Filesystem (WSFS) explorer, alongside the existing folder-creation and upload commands. Users can now create a file from the view toolbar or from a directory/repo context menu, name it via the existing wizard, and have it open automatically in the editor.

Tests

Updated WorkspaceFsCommands.test.ts

@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: 1922
  • Commit SHA: 10be4b09b9dd76600c95dc5bdbba830318c3335f

Checks will be approved automatically on success.

@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.

Solid addition — the command wiring, menu placement, and toolbar-vs-context-menu target resolution cleanly mirror the existing createFolder/uploadFile patterns, and the test coverage is thorough. One correctness/consistency issue should be addressed before merge, plus a couple of minor UX nits (left inline).

Main issue — the .ipynb-only heuristic is too narrow. doCreateFile decides everything from inputName.endsWith(".ipynb"), but the SDK imports with format: "AUTO" and WorkspaceFsDir.createFile strips a broader set on lookup: (py|ipynb|scala|r|sql). That regex is the SDK telling us .py/.scala/.r/.sql are also stored as notebooks (extension dropped). Consequences for e.g. script.py:

  1. It lands in the editor branch and opens created.path (the stripped notebook path) as a text document — inconsistent with .ipynb, which opens in the browser.
  2. The existence pre-check looks at ${root}/script.py while the notebook lands at ${root}/script, so the clash is missed and — since createFile(..., true) passes overwrite=true — an existing notebook is silently overwritten with no prompt. (doUploadFile shares this gap, so it's pre-existing, but worth not propagating.)

Recommend deciding the open mode from the created entity via the already-imported WorkspaceFsUtils.isNotebook(created) instead of the extension string, and widening the existence-check stripping to the SDK's set. See inline comments.

Heads-up on tests: the test fake's createFile only strips .ipynb, so the suite is green but wouldn't catch the above. If you switch to isNotebook(created), please add a test where the fake returns a NOTEBOOK-typed entity for a .py name.

});
this.fsp.notifyCreated(uri);

if (isIpynb && created) {

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.

This open-mode decision keys off isIpynb, but WorkspaceFsDir.createFile strips (py|ipynb|scala|r|sql) on lookup — so a .py/.sql/.scala/.r file is also stored as a notebook (extension dropped), and created.path here is the stripped path. Those fall into the editor branch below and get opened as a text document at the stripped notebook path, inconsistent with .ipynb.

Suggest deciding from the actual entity instead of the extension — WorkspaceFsUtils is already imported and isNotebook exists:

if (created && WorkspaceFsUtils.isNotebook(created)) {
    try { await this.openInBrowser(created); }
    catch (e: unknown) { ctx?.logger?.error(`Can't open ${inputName} in browser after creation`, e); }
    return;
}

This removes the brittle string check entirely and makes .py-as-notebook behave like .ipynb.

}

const isIpynb = inputName.toLowerCase().endsWith(".ipynb");
const existingName = isIpynb

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.

The existence check only strips .ipynb, but the SDK stores (py|ipynb|scala|r|sql) at the extension-stripped path. So creating script.py when a script notebook already exists won't detect the clash, won't prompt, and — because createFile(..., true) overwrites — silently destroys the existing notebook. Consider stripping the same extension set the SDK does (/\.(py|ipynb|scala|r|sql)$/i) for this lookup.

return;
}

const inputName = await createDirWizard(

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.

Non-blocking: createDirWizard is folder-oriented when reused for filenames — it pre-fills the input value/placeHolder with the project folder basename (an odd default for a new file) and its validation returns "Invalid name: Folders cannot contain '/'". Consider a file-appropriate default and neutral wording.

"group": "navigation@1"
},
{
"command": "databricks.wsfs.createNewFile.toolbar",

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.

Nit (optional): this toolbar button shares navigation@1 with createFolder.toolbar and uploadFile.toolbar, so ordering between the three is implicit. The context-menu entries use explicit wsfs_mut@0/@1/@2; consider the same explicit ordering here for predictability. Pre-existing pattern, so optional.

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