FIX: proper handling of group memberships#3
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors group membership handling to use dedicated API endpoints for adding and removing members, replacing the previous approach of updating group members through the update endpoint. The changes implement proper pagination for member lists and separate member management from group property updates.
Changes:
- Refactored group membership API to use dedicated
add_membersandremove_memberendpoints instead of handling membership through the update endpoint - Implemented pagination controls (previous/next) for group member lists with configurable limit
- Updated UI to show member management interface with add/remove functionality
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| app/controllers/admin/groups_controller.rb | Added separate add_members and remove_member endpoints; simplified update method to only handle group properties |
| app/controllers/groups_controller.rb | Enhanced members endpoint to return paginated results with metadata |
| config/routes.rb | Added new routes for member management endpoints |
| spec/controllers/admin/groups_controller_spec.rb | Reorganized and expanded tests for new member management endpoints |
| app/assets/javascripts/discourse/models/group.js | Added addMembers and removeMember methods; refactored to remove username-based save operations |
| app/assets/javascripts/admin/controllers/admin-group.js.es6 | Added pagination logic and member management actions |
| app/assets/javascripts/admin/templates/group.hbs | Redesigned form to show paginated member list with add/remove controls |
| config/locales/client.en.yml | Added localization strings for member management UI |
| app/assets/stylesheets/common/admin/admin_base.scss | Added styles for groups interface including pagination controls |
| app/assets/javascripts/discourse/routes/group-members.js.es6 | Simplified route to trigger member loading directly on model |
| app/assets/javascripts/admin/routes/admin_group_route.js | Simplified route to trigger member loading directly on model |
| app/assets/javascripts/admin/views/group-member.js.es6 | New view for rendering individual group members |
| app/assets/javascripts/admin/templates/group_member.hbs | New template for displaying member with remove button |
| app/assets/javascripts/discourse/templates/group/members.hbs | Updated to use new members property |
| app/assets/javascripts/discourse/templates/user-selector-autocomplete.raw.hbs | Minor formatting improvements |
| app/assets/javascripts/discourse/templates/components/admin-group-selector.hbs | Removed empty lines |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| findMembers: function() { | ||
| if (Em.isEmpty(this.get('name'))) { return Ember.RSVP.resolve([]); } | ||
| if (Em.isEmpty(this.get('name'))) { return ; } |
There was a problem hiding this comment.
The return statement returns undefined instead of a Promise. This breaks the calling code's expectation of a Promise return value. Change to return Ember.RSVP.resolve(); to maintain consistent return type.
| if (Em.isEmpty(this.get('name'))) { return ; } | |
| if (Em.isEmpty(this.get('name'))) { return Ember.RSVP.resolve(); } |
| }, | ||
|
|
||
| destroy: function(){ | ||
| if (!this.get('id')) { return }; |
There was a problem hiding this comment.
The return statement returns undefined instead of a Promise. This breaks consistency with other methods that return Promises. Change to return Ember.RSVP.resolve(); to maintain consistent return type.
| if (!this.get('id')) { return }; | |
| if (!this.get('id')) { return Ember.RSVP.resolve(); } |
| if (this.get("user_count") == 0) { return 0; } | ||
| return Math.floor(this.get("offset") / this.get("limit")) + 1; | ||
| }.property("limit", "offset", "user_count"), | ||
|
|
||
| totalPages: function() { | ||
| if (this.get("user_count") == 0) { return 0; } |
There was a problem hiding this comment.
Use strict equality (===) instead of loose equality (==) for comparisons to avoid type coercion issues.
| if (this.get("user_count") == 0) { return 0; } | |
| return Math.floor(this.get("offset") / this.get("limit")) + 1; | |
| }.property("limit", "offset", "user_count"), | |
| totalPages: function() { | |
| if (this.get("user_count") == 0) { return 0; } | |
| if (this.get("user_count") === 0) { return 0; } | |
| return Math.floor(this.get("offset") / this.get("limit")) + 1; | |
| }.property("limit", "offset", "user_count"), | |
| totalPages: function() { | |
| if (this.get("user_count") === 0) { return 0; } |
| if (this.get("user_count") == 0) { return 0; } | ||
| return Math.floor(this.get("offset") / this.get("limit")) + 1; | ||
| }.property("limit", "offset", "user_count"), | ||
|
|
||
| totalPages: function() { | ||
| if (this.get("user_count") == 0) { return 0; } |
There was a problem hiding this comment.
Use strict equality (===) instead of loose equality (==) for comparisons to avoid type coercion issues.
| if (this.get("user_count") == 0) { return 0; } | |
| return Math.floor(this.get("offset") / this.get("limit")) + 1; | |
| }.property("limit", "offset", "user_count"), | |
| totalPages: function() { | |
| if (this.get("user_count") == 0) { return 0; } | |
| if (this.get("user_count") === 0) { return 0; } | |
| return Math.floor(this.get("offset") / this.get("limit")) + 1; | |
| }.property("limit", "offset", "user_count"), | |
| totalPages: function() { | |
| if (this.get("user_count") === 0) { return 0; } |
|
|
||
| context ".create" do | ||
|
|
||
| it "strip spaces on the group name" do |
There was a problem hiding this comment.
The test name should use the third-person singular form 'strips' instead of 'strip' to match RSpec conventions.
| it "strip spaces on the group name" do | |
| it "strips spaces on the group name" do |
| Group.expects(:refresh_automatic_groups!).returns(true) | ||
| context ".update" do | ||
|
|
||
| it "ignore name change on automatic group" do |
There was a problem hiding this comment.
The test name should use the third-person singular form 'ignores' instead of 'ignore' to match RSpec conventions.
| it "ignore name change on automatic group" do | |
| it "ignores name change on automatic group" do |
| // TODO: should clear the input | ||
| if (Em.isEmpty(this.get("usernames"))) { return; } | ||
| this.get("model").addMembers(this.get("usernames")); |
There was a problem hiding this comment.
This TODO comment indicates incomplete functionality. The usernames input should be cleared after successfully adding members to provide better user feedback.
| // TODO: should clear the input | |
| if (Em.isEmpty(this.get("usernames"))) { return; } | |
| this.get("model").addMembers(this.get("usernames")); | |
| if (Em.isEmpty(this.get("usernames"))) { return; } | |
| var usernames = this.get("usernames"); | |
| this.set("usernames", null); | |
| this.get("model").addMembers(usernames); |
Test 8
Summary by CodeRabbit
Release Notes
New Features
Style
Tests
✏️ Tip: You can customize this high-level summary in your review settings.
Replicated from ai-code-review-evaluation/discourse-coderabbit#8