Repository navigation
feat(desktop): add native file handling and Explorer improvements - #269
ThisIs-Developer merged 24 commits into
Conversation
|
@Kechos23 is attempting to deploy a commit to the Developer Labs Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
… linked workflows
55ca88e to
73f5567
Compare
|
Hello @ThisIs-Developer, if you would like to evaluate these features together, I can point you to the custom Windows release used for our manual testing. It demonstrates single-instance file opening and native drag-and-drop with the choice between linking the original and creating a Workspace copy. If you are comfortable maintaining a custom Neutralino build, this could also serve as an interim option while the upstream runtime changes are pending. However, it is not a maintenance-free alternative to updating Neutralino: security fixes and future runtime updates would still need to be incorporated and retested. There is no expectation to adopt or distribute that runtime. Keeping this PR as a draft/demo until official support becomes available is equally reasonable. |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
Hi @Kechos23! 👋 I've made quite a few updates to this PR, and I wanted to share the full list with you. Most of the changes are related to your original vision for this PR. I've mainly focused on fixing issues, improving the existing functionality, and polishing the overall experience. I've also included some additional Explorer and UI/UX improvements that I felt were needed. Rather than creating separate PRs for these smaller changes, I thought it would be better to address them together. I'd really appreciate it if you could review all these changes, including the new features I've added. Since this PR started with your vision, I genuinely value your feedback and suggestions. I want to make sure the changes align with what you originally intended and that the additional improvements make sense to you. Please take your time reviewing everything. There's absolutely no rush. Feel free to point out anything you think should be changed, improved, or reconsidered. I'm happy to make further adjustments based on your feedback. Once you've reviewed everything and we're both happy with the result, I'd like to merge this PR and move forward with the next improvements. Thanks again for your time! 🙌 |
|
Here's a summary of everything I've updated: 1. Main Changes (Related to Your PR Vision)
2. Additional Changes (Explorer & UI/UX)
|
Kechos23
left a comment
There was a problem hiding this comment.
Thanks for the updates! I reviewed the latest changes with assistance from Codex, focusing on data safety and recovery. Two points came up:
-
Secret Workspace — saving while locking: an import can queue another save while locking is still in progress. That queued save may run after the unlocked documents have been removed from memory and interpret the empty workspace as deletions. The underlying save/lock behavior already exists in
main; the new import flows provide another way to encounter it. -
Linked-file rename — interrupted operation: the original is renamed before the updated link is persisted. A crash or lost native response between those steps can leave the workspace pointing to the old path. The file itself remains intact, so I consider this a lower-priority recovery improvement.
These findings were reproduced in controlled simulations using the relevant application functions, rather than through the packaged EXE. In particular, the Secret Workspace scenario deserves confirmation in the full application.
The proposed fixes are in the inline suggested-change comments, together with the reasoning and validation cases. Please review and adapt them as appropriate.
Another idea I've been considering is an explicit “Open in new window” option for opening a file in a second window when desired, while keeping the current single-instance behavior by default. Handling shared workspace state, drafts and concurrent edits safely could make this a substantial addition, so it would probably be better explored later in a separate PR. I'd be interested in your feedback on whether this would be useful and how you would approach it.
| let linkedSourceMonitoringChain = Promise.resolve(); | ||
| const linkedSourceSavePaths = new Set(); | ||
| let linkedReadEpoch = 0; | ||
| let explorerRename = null; |
There was a problem hiding this comment.
Secret Workspace: coordinate locking with queued saves and imports
This is pre-existing shared save/lock behavior, exposed by the new asynchronous import flows, rather than a regression introduced solely by this PR.
Controlled sequence with the current application functions and an in-memory storage double:
- Start locking; hold encryption of an existing secret document.
- Complete another import and queue its encrypted flush.
- Release the first save. Lock removes the unlocked tabs.
- The queued save then reads an empty payload, deletes the existing record, and commits
documentCount: 0.
Proposed coordinated fix — do not apply the declaration below on its own. The shared functions below are outside this PR's changed hunks, so I am including their required edits explicitly rather than pretending this one suggestion fixes everything.
| let explorerRename = null; | |
| let explorerRename = null; | |
| let secretWorkspaceLockInProgress = false; |
Required companion changes in script.js:
- In
enqueueSecretWorkspaceSave, revalidate the captured key inside the queued callback, at each conflict retry, and again after asynchronous encryption immediately beforeapplySecretRecordChanges:
if (!isSecretWorkspaceUnlocked() || secretWorkspaceKey !== key) return false;- In
lockSecretWorkspace, synchronously set the lock-in-progress flag before awaiting the flush. Preserve/restore the app container's previous inert state infinally; aborting a flush must keep the workspace unlocked and its documents intact. The existing lock body belongs inside thetry:
if (!isSecretWorkspaceUnlocked() || secretWorkspaceLockInProgress) return;
secretWorkspaceLockInProgress = true;
const container = document.querySelector('.app-container');
const previousInert = Boolean(container && container.inert);
if (container) container.inert = true;
try {
// Existing save/flush/remove-tabs/clear-key lock body.
} finally {
secretWorkspaceLockInProgress = false;
if (container) container.inert = previousInert;
}- In
createImportedDocument, refuse Secret imports while locking:
if (targetLocation.workspaceId === SECRET_WORKSPACE_ID &&
(secretWorkspaceLockInProgress || !isSecretWorkspaceUnlocked())) return null;- Apply the same lock-in-progress check to the Secret target checks in both browser
handleDrop.canApplyand nativeprocessNativeDrop.canApply, so an in-progress folder import cancels before adding more items. Retain the existing encrypted flush on successful completion.
The core guard/lock draft passed four isolated regression checks: lock + concurrent import + queued save retains existing records; failed encryption retains documents and restores controls; an old queued save cannot enter a new unlock session; a session change during encryption cancels before storage mutation. These used the actual extracted functions with controlled storage/crypto doubles, not the EXE. Please also verify actual browser/native imports, Private mode, lock failure, and lock/unlock before accepting the coordinated changes, and regenerate the desktop resources from the root source.
| await workspaceStorage._desktopCheckMovePaths(source, destination); | ||
| if (!tabs.includes(tab) || tab.sourcePath !== source) throw new Error('Link changed'); | ||
| captureLiveLinkedDraft(tab); | ||
| await Neutralino.filesystem.move(source, destination); |
There was a problem hiding this comment.
Linked rename: preserve durable intent before the external filesystem mutation
With a simulated native response loss after a successful disk rename, move rejects and the metadata update below never runs: the file is at the new path, while both the live and persisted link still point to the old path. A process interruption at the same boundary leaves the same recovery gap. This does not delete the original content.
Suggested recovery change: treat this as a coordinated write-ahead/recovery feature, rather than adding a catch that guesses success:
- Before
filesystem.move, commit and verify the current draft plus a rename-intent record containing the document ID, old/new paths and a source identity/content fingerprint. Abort before touching the original if that durable commit fails or persistence is unavailable (including Private mode). - Recheck the source/link and destination after that asynchronous commit; then perform the existing no-overwrite move.
- Persist the new linked metadata before clearing the intent.
- On startup or an uncertain native response, inspect the saved intent without replaying the move. Repair the link only when the outcome can be established safely. Both paths present, neither path present, unreadable/changed content, case aliases or a destination already linked elsewhere must remain an explicit recovery decision. Never automatically overwrite, delete or roll back an external file.
Do not reuse the current Vault move-recovery branch unchanged: it is deliberately scoped to paths inside the managed Vault, whereas these originals are external. Recovery records also need validation and must not cause restored/imported backups to silently reconnect external paths.
Validation cases: crash before move, crash after move/before metadata commit, lost response after a successful move, metadata-save failure, occupied destination, case-only rename, and newer local/external edits. Preserve draft bytes and both originals in every ambiguous case.
This is a proposed recovery protocol, not a tested drop-in implementation; I have not fabricated a one-click code patch for the startup/storage work. The failure sequence was reproduced in a controlled simulation, while the full recovery feature still needs implementation and EXE validation.
|
Hi @Kechos23, I saw the inline suggestions and clicked Apply changes, but I don't think anything actually changed. Could you please check whether the suggestions were applied successfully? If not, could you please implement the fixes for both issues you identified and submit them? Regarding Open in new window, could you elaborate a little more on how you envision it working? For example, would the new window display only the selected document, or would other documents and workspaces also be accessible? How would synchronization between windows work? I think we need to consider these aspects carefully. It sounds like a useful feature, but I believe it would be better to explore it separately in a future PR. Thank you! |
|
Thank you for all the time you've put into reviewing my PRs and for the fixes, additions and polish you've contributed. I really appreciate the care you're giving this work. You were right: the earlier one-click suggestion only added the guard variable; the accompanying instructions required additional implementation. Sorry for the confusion. I've now implemented both fixes and pushed them to this PR as separate commits:
Validation passed: 249 unit tests and 234 Chromium tests, including simulated interruption/restart, lost replies, storage failures and actual temporary Windows filesystem checks. This does not replace hands-on acceptance of the packaged EXE. The existing CI build has been triggered. Regarding Open in new window, my initial thought is an explicit action on a selected document, while normal launches continue using the existing window. I haven't settled whether the second window should expose the full workspace or just that document. Shared workspace state, separate drafts and concurrent saves need careful design. The idea came to mind for dual-monitor setups, where users might want several documents open and editable at the same time across both screens. I'll think through the behavior more carefully and come back to it in the future. On a separate note, I've also done some initial exploration related to #280, which I can share there whenever you're ready to revisit it—no rush. |
|
Hi @Kechos23, Thank you for looking into the issues and implementing the fixes! I believe everything is now resolved, so I'll go ahead and merge the PR. Thanks again for your time and valuable contribution! The changes will be available in the desktop version soon. 🚀 |
Latest UI refinements
.md/.markdownextension on disk.No manual tests were run for these requested changes. Existing rename automation was updated for the new extension-free input contract; the repository's configured CI runs automatically on push.
Purpose
Add opt-in Windows native file/folder drops with real paths and forward subsequent Markdown launches to the existing window. Explorer targets distinguish independent Vault copies from links to originals, while preserving open documents, internal moves and media imports. Shared web/desktop improvements add consistent drag feedback, inline rename and web folder downloads.
The branch includes v3.10.5/main at
b14a2436; the Linked Workspace and safety prerequisites from #262/#279 are merged. Native runtime/client pins in the standard release remain unchanged. Standard Windows packaging now applies application branding using pinned packaging dependencies.Changes
Windows executable
Download the Windows x64 package from the successful Windows build.
c092cf8dea87d52f7474416cbd427781ed889824Markdown-Viewer-PR269-c092cf8d-win_x64.exe72091fa69dc9b31c0010fb1fbb6881bf3cd0fee4cc2d6566b7bddcc57d3d8f33b854294e76d6d2a260373631713e81eeff3234e52509c1ccba6f10dc08765f083.10.5.0; application/window identity: Markdown Viewercom.markdownviewer.desktop.native-demoDocuments/Markdown Viewer Native Demo VaultThe separate ID/Vault protects normal-release storage; the title and application presentation have no demo suffix. The self-contained EXE requires WebView2, as the standard app does. Close older trials first because trial copies share their Vault. Saving or renaming a Linked file changes its original.
The optional registration helper must remain beside the EXE in its chosen portable location. Markdown associations now use the official application icon. Explorer controls tooltip labels, dates and size; executable metadata supplies the correct name/version.
Validation
The existing Windows CI build runs automatically after each push. No manual tests were run for this refinement at the maintainer's request. Earlier browser and native evidence remains documented in the preceding review; those browser cases were not rerun for this update.
The final Windows build completed successfully. The downloaded app/helper match their provenance hashes. Read-only inspection confirms blank CompanyName fields, the existing application icon resource and no Phosphor text in the app binary.
The current Vercel preview and Docker build pass. CodeRabbit's final review is still pending.
Acceptance boundaries
No further reproducible defect was found in the reviewed/tested paths after the fixes. This supports review of the opt-in implementation, not unconditional enterprise release certification.
Build and behavior notes · Integration and browser limits
Contributor demonstrations
Single instance:
https://github.com/user-attachments/assets/af14e78c-ccf9-4ec5-b5da-a857dac867b4
Native drop:
https://github.com/user-attachments/assets/22e4f06f-3564-4604-adb3-5302e68c9f84