Add create file support to WSFS explorer#1922
Conversation
anton-107
left a comment
There was a problem hiding this comment.
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:
- 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. - The existence pre-check looks at
${root}/script.pywhile the notebook lands at${root}/script, so the clash is missed and — sincecreateFile(..., true)passesoverwrite=true— an existing notebook is silently overwritten with no prompt. (doUploadFileshares 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) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
using WorkspaceFsUtils.isNotebook(created) to detected if created file was notebook
| } | ||
|
|
||
| const isIpynb = inputName.toLowerCase().endsWith(".ipynb"); | ||
| const existingName = isIpynb |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
When creating new file, content is empty string "" for .sql, .py, .scala, .r etc.. so it ends up with type FILE, not converted to notebook type automatically. so extension will not be stripped, and no silent overwrite will happen.
in case of ipynb file, valid empty notebook content (json) is provided, so it will be converted to notebook format, that's the reason why we check it explicitly
| return; | ||
| } | ||
|
|
||
| const inputName = await createDirWizard( |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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.
|
Looks good from my side, I let @anton-107 to make a pass before approving. |
anton-107
left a comment
There was a problem hiding this comment.
Follow-ups all addressed — approving.
- Open-mode decision: now branches on
WorkspaceFsUtils.isNotebook(created)instead of the extension string, so the open path is driven by the actual created entity. My main concern is resolved. - Existence-check stripping: confirmed correct for this flow — new files are created with empty content, so
.py/.sql/.scala/.rimport as plainFILEs with the extension preserved (only.ipynbconverts to a notebook at the stripped path). The created-path and lookup keys stay consistent, so the silent-overwrite case can't occur here. The narrow.ipynbstripping is the right choice. - Toolbar regression (selecting a file/notebook):
getValidRootrejects a non-directory target with a clear message, so it's a graceful error rather than a crash.
Remaining items are cosmetic (folder-oriented createDirWizard wording for filenames; implicit navigation@1 toolbar ordering) and non-blocking.
|
If integration tests don't run automatically, an authorized user can run them manually by following the instructions below: Trigger: Inputs:
Checks will be approved automatically on success. |
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