feat(sidebar): Add conversation sections and sort options - #17368
feat(sidebar): Add conversation sections and sort options#17368Rikdekker wants to merge 14 commits into
Conversation
19bd9ad to
ba23a61
Compare
Allow users to organize conversations into custom sections with drag-and-drop reordering, and sort conversations by recent activity, alphabetical order, or groups first. Resolves nextcloud#12025 Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add type assertions in template to satisfy TypeScript type checker for union type ListItem (Conversation | SectionHeaderItem). Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix import ordering, member delimiter style, missing JSDoc comments, unnecessary parentheses, and sorted named exports. Add mock for conversationSectionsService in LeftSidebar tests to prevent network errors during test execution. Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Rikdekker <Rikdekker@users.noreply.github.com>
Revert version back to 24.0.0-dev.2 (matching main branch) to fix "App not compatible with this version" error in integration tests. Add missing section_id key to ChatManagerTest attendee data arrays to fix "Undefined array key" PHP warning. Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Rikdekker <Rikdekker@users.noreply.github.com>
Update min-version and max-version to 34 to match the main branch target, fixing integration test failures. Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Rikdekker <Rikdekker@users.noreply.github.com>
293f1aa to
224cbd8
Compare
nickvergessen
left a comment
There was a problem hiding this comment.
This is a huge step 😎
However it will prevent a conversation from being in multiple sections, which we had planned. Not sure if it's better to merge like this already, or if we should try a second PR based on the current one that tries to make it possible to have 1toN mapping available
|
Also to be able to review easier, we'd appreciate if you address comments in individual commits going forward. we can rebase and combine them at the end, but it avoids having to recheck the full diff all the time :) |
|
Thanks for the review! 🙏 Will address all comments in individual commits. Regarding 1:1 vs 1:N section mapping: I believe 1:1 is the right model for sections — they behave like folders, not labels. A few observations:
If cross-cutting organization is ever needed, a separate tagging system would be more appropriate than multi-section — tags and folders solve fundamentally different problems. Happy to discuss further if you see use cases I'm missing! |
Add userId to findById() and clearSectionFromAttendees() to ensure sections can only be accessed/modified by their owner at the query level, preventing insecure direct object reference vulnerabilities. Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Rikdekker <Rikdekker@users.noreply.github.com>
Replace autoincrement with Snowflake ID pattern for the talk_conversation_sections table, matching the scheduled messages table design. Rename index to tcs_user_id. Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Rikdekker <Rikdekker@users.noreply.github.com>
Remove docs/conversation-sections.md (documentation is in OpenAPI specs). Revert CHANGELOG.md changes (done manually on release). Move capabilities entries from 23.x to section 24. Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Rikdekker <Rikdekker@users.noreply.github.com>
Well that is basically exactly the problem 😅
yeah, but you can have "folder behaviour" with tag API, but not the other way around.
This can be adjusted of course. I'll discuss it with the team next week |
nickvergessen
left a comment
There was a problem hiding this comment.
Frontend
-
we are migrating away from Vuex store, sortMode implementation can be moved to Pinia store settings.ts
-
UI: Filter + Sort buttons taking too much space, we can merge them into single entry point, with NcActionSeparator inside. Shared icon could be https://pictogrammers.com/library/mdi/icon/filter-cog-outline/ or https://pictogrammers.com/library/mdi/icon/filter-variant/
Design
-
Having a separate "Manage sections" entry at the bottom is lessening the already reduced vertical space, instead we can have a 3 dot menu button that appears on hover, with edit/reorder/delete which leads to the modal with that section in an editable state
Sample from mail app: https://github.com/user-attachments/assets/41903e40-116c-4871-a288-e3442ef9749c -
It seems the headers are not using our components
-
In the "Manage sections" modal

- each item seems to be taller than usual? Possibly it's 44px instead of default clickable area.
- To create a new section feels not accessible and inconsistent with how it's usually done in NC (lack of a button, only a text field with a placeholder, etc), we should add an explicit button, and then a text field
- There should also be "move up" and "move down" buttons in the 3 dot menu for a11y
-
Wording should be category / tag / label instead of "section"
We can also take over the Pull Request to address the feedback ourselves in case it's too much for you.
Addresses all review feedback from nextcloud#17368: **Rename & terminology:** - Rename "sections" to "categories" throughout (backend, frontend, API) - API endpoints: /sections → /categories **Backend:** - IDOR fix: userId parameter on mapper queries - Snowflake ID for primary key - category_ids as TEXT/JSON column (single category per conversation) - Sort order and group mode as server-side user preferences - Consistent string-based ID handling for Snowflake IDs **Frontend:** - Merge filter + sort into single dropdown with NcActionSeparator - Split sort (activity/alphabetical) and group (type-first) into separate settings - Migrate sortMode from Vuex to Pinia settings store - Use NcAppNavigationItem with allowCollapse for category headers - Inline category management via 3-dot menu (rename, move up/down, delete) - New category creation via filter/sort dropdown - Delete confirmation using Nextcloud ConfirmDialog - Move up/down disabled on first/last category - Conversations move to "Other" when category is deleted (instant UI update) **Cleanup:** - Remove ManageSectionsDialog (replaced by inline management) - Remove standalone docs (use OpenAPI specs) - Revert CHANGELOG.md and appinfo/info.xml changes - Regenerate OpenAPI specs and TypeScript types Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Thank you for the thorough review @nickvergessen! We've addressed all feedback points in this commit. Inline comment responses
Review body responses
ScreenshotsCreating a new category via the filter/sort dropdown:
Assigning a conversation to a category and the result:
|
Addresses all review feedback from nextcloud#17368: **Rename & terminology:** - Rename "sections" to "categories" throughout (backend, frontend, API) - API endpoints: /sections → /categories **Backend:** - IDOR fix: userId parameter on mapper queries - Snowflake ID for primary key - category_ids as TEXT/JSON column (single category per conversation) - Sort order and group mode as server-side user preferences - Consistent string-based ID handling for Snowflake IDs **Frontend:** - Merge filter + sort into single dropdown with NcActionSeparator - Split sort (activity/alphabetical) and group (type-first) into separate settings - Migrate sortMode from Vuex to Pinia settings store - Use NcAppNavigationItem with allowCollapse for category headers - Inline category management via 3-dot menu (rename, move up/down, delete) - New category creation via filter/sort dropdown - Delete confirmation using Nextcloud ConfirmDialog - Move up/down disabled on first/last category - Conversations move to "Other" when category is deleted (instant UI update) **Cleanup:** - Remove ManageSectionsDialog (replaced by inline management) - Remove standalone docs (use OpenAPI specs) - Revert CHANGELOG.md and appinfo/info.xml changes - Regenerate OpenAPI specs and TypeScript types Signed-off-by: Rikdekker <Rikdekker@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1ba676a to
b500d87
Compare
Addresses all review feedback from nextcloud#17368: **Rename & terminology:** - Rename "sections" to "categories" throughout (backend, frontend, API) - API endpoints: /sections → /categories **Backend:** - IDOR fix: userId parameter on mapper queries - Snowflake ID for primary key - category_ids as TEXT/JSON column (single category per conversation) - Sort order and group mode as server-side user preferences - Consistent string-based ID handling for Snowflake IDs **Frontend:** - Merge filter + sort into single dropdown with NcActionSeparator - Split sort (activity/alphabetical) and group (type-first) into separate settings - Migrate sortMode from Vuex to Pinia settings store - Use NcAppNavigationItem with allowCollapse for category headers - Inline category management via 3-dot menu (rename, move up/down, delete) - New category creation via filter/sort dropdown - Delete confirmation using Nextcloud ConfirmDialog - Move up/down disabled on first/last category - Conversations move to "Other" when category is deleted (instant UI update) **Cleanup:** - Remove ManageSectionsDialog (replaced by inline management) - Remove standalone docs (use OpenAPI specs) - Revert CHANGELOG.md and appinfo/info.xml changes - Regenerate OpenAPI specs and TypeScript types Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix arrow function spacing: `fn($id)` → `fn ($id)` (php-cs-fixer) - Wrap array_filter/array_map in array_values() for psalm list type - Add sort-order and group-mode to CapabilitiesTest expectations and mocks Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…arning) - Add psalm type annotation for json_decode result in ConversationCategoryMapper - Handle missing category_ids key in AttendeeMapper::createAttendeeFromRow Signed-off-by: Rikdekker <rik@shalution.nl> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
b500d87 to
b37ee63
Compare
Antreesy
left a comment
There was a problem hiding this comment.
Looking nice now!
Left some comments to address, feel free to discuss if you have questions or concerns on some of those
Addresses all 19 review comments: - Add PRIVATE_FIRST group mode and rename TYPE_FIRST to GROUPS_FIRST - Bump version to dev.24 and set min-version to NC33 - Move sorting logic from conversationsStore to LeftSidebar (perf) - Import ConversationCategory type from OpenAPI spec - Fix test mock to use generateOCSResponse - Remove isFavorite/isArchived restriction on category assignment - Multi-category support (1:N): checkboxes, backend accepts array - Move category methods from LeftSidebar to store/header components - Uniform collapsed state for favorites/other via store - Revert class name change (filters-and-sort -> filters) - Fix empty space in settings button container - Simplify ConversationsListVirtual with single item prop - Refactor store: reactive + BrowserStorage cache, drop initialised - Fix SnowflakeID comment in ResponseDefinitions.php Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Review feedback addressedAll 19 review comments from @Antreesy have been implemented in the latest commit: Changes summary
HandoverThis PR is ready for the Nextcloud team to take over. Feel free to adjust, refactor, or split as needed. We're available for questions but won't be making further changes from our side. |
- Regenerate OpenAPI specs after ResponseDefinitions change - Fix formatCategory: remove collapsed field, cast id to string - Fix LeftSidebar test to expect favorites-first sort order - Update category ID types from number to string (SnowflakeID) Signed-off-by: Rikdekker <Rikdekker@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Rikdekker <Rikdekker@users.noreply.github.com>
|
Thanks for the contribution, @Rikdekker 🎉 |
|
Hello there, We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process. Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6 Thank you for contributing to Nextcloud and we hope to hear from you soon! (If you believe you should not receive this message, you can add yourself to the blocklist.) |
I said "Feel free to adjust, refactor, or split as needed.", but now it is renamed to Tags. It is a grouping snd not a tag in my opinion. Also very disappointed that the filtering didn't make it. Or is this just beta for NC34 and subject to change?
|
Tags are known from other apps (e.g. Files), so decision was made to rename it
I don't remember we lost something on the way (apart from 'New category' button, but it was moved to conversation actions > Tags). What filtering did you mean? |
I don't agree with the rename, because I think a tag is a sort of metadata of file/converstations ("below") and in this case it is a "higher" level. To group/categorise. But that is just an opinion. ;-) I was confused by filtering and sorting. The sorting is there. |






Summary
Resolves #12025
Backend
talk_conversation_sectionstable withid,user_id,name,sort_order,collapsedcolumnsConversationSectionControllerwith full CRUD + reorder API (/api/v4/sections)sectionIdfield onAttendeemodel to assign conversations to sectionsconversation-sectionsFrontend
ConversationSectionHeadercomponent for collapsible section headersManageSectionsDialogwith drag-and-drop reorderingconversationSectionsPinia storeScreenshots
Test plan
🤖 Generated with Claude Code