feat(folders): add folder management - #729
Merged
Merged
Conversation
Folders are tags: emptying one leaves its row forever with no way to remove it.
Add FolderRepository.findAllFolders (flat list with document count, subfolders
kept as their own rows) and DocumentsService.deleteFolders, which drops the
DocumentsFolders rows explicitly since foreign keys are off on this database,
then notifies EVENT_FOLDER_DELETED so the main list refreshes.
folderUtils holds the pure cascade rule ("work" also takes "work/2024", never
"workshop") so it can be unit-tested outside the NativeScript runtime.
Refs #684
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add Settings > Folders > "manage folders": lists every folder with its document count, including the empty ones the main list hides, and deletes them from a selection toolbar or in bulk through "delete empty folders". Deleting cascades to subfolders since they only exist through their name. When documents are involved the confirmation lets the user keep them — they go back to the root list — or delete them, honouring the trash setting. Refs #684 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Folder sync was a plain union: a folder missing locally was recreated from the remote manifest, so deleting one always came back on the next both-ways sync. Mirror the document tombstones for folders: deleting a folder queues its id per service, the ids land in a deleted_folders.json manifest, and both sync directions drop tombstoned folders from the remote list instead of resurrecting them - the both-ways pass also deletes them locally, which propagates a deletion made on another device. Generalise mergeDeletedDocumentTombstones into mergeTombstones so folders reuse it with numeric ids, keeping the document wrapper and its behavior unchanged. Refs #684 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Moving a document to "a/b" only created the "a/b" row, but the folder list groups by first path component and drops every entry whose name still contains a slash - so the group had no row to render and the document disappeared from both the folder list and the root list. Create the missing ancestors whenever a folder name introduces them, on move and on rename, and backfill existing databases through a migration so already orphaned documents show up again. Refs #684 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deleting a folder while keeping its documents unfiles them, so they belong to the root list, but the list only rebuilt its folder rows and the documents stayed hidden until the next app start. Refresh the whole list instead, and leave the folder view when the folder it shows is the one being deleted. Refs #684 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replacing the items array reaches the collectionview refresh() from inside onBindViewHolder, where notifyDataSetChanged throws IllegalStateException: the list crashed when a document was moved between folders while cells were binding. Patch ui-collectionview 6.0.26 (upstream PR nativescript-community/ui-collectionview#106) to defer such a refresh to the layout callback fired after super.onLayout, with a one-shot OnPreDrawListener for the scroll case, and to keep serving the data the running pass started with. Follows the svelte-check patch already in this repo; drop it once the fix ships upstream. Guard itemTemplateSpanSize against a missing item, like the CardsList template selector already does. Refs #684 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The one-way folder sync pushed a folder as its JSON string, so the manifest ended up holding a string where every other path stores an object. Such an entry matches no local folder by id: it is pushed again on every sync, it cannot be matched by the deleted folder tombstones, and a both-ways sync tries to create a local folder out of it. Refs #684 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
DocumentsFoldersrows are removed explicitly, since foreign keys are off on this database and the declaredON DELETE CASCADEnever fires.deleted_documents.jsonmechanism.work/2024) created only that row, and since the folder list groups by first path component and drops names containing a slash, neither the folder nor the document showed up anywhere. Missing ancestors are now created, with a migration backfilling existing databases.ui-collectionview6.0.26 so replacing the items array from insideonBindViewHolderno longer throwsIllegalStateException(upstream: fix(android): do not refresh while the RecyclerView computes its layout nativescript-community/ui-collectionview#106). Drop the patch once that ships.Testing
yarn test(307 passing) — new unit tests cover the folder cascade/ancestor helpers and the folder tombstone merge; each was mutation-checked.yarn svelte-checkclean, eslint clean on the changed files.ns run android --clean), not a livesync. Worth exercising: delete an empty folder, delete one holding documents with both answers, delete a parent holding subfolders, and a two-device sync where a folder deleted on A disappears on B.Refs #684
🤖 Generated with Claude Code