feat: enforce feature ownership project setting#7067
feat: enforce feature ownership project setting#7067gagantrivedi wants to merge 8 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
aca43a4 to
1749d8d
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7067 +/- ##
========================================
Coverage 98.33% 98.34%
========================================
Files 1337 1336 -1
Lines 50010 50132 +122
========================================
+ Hits 49178 49302 +124
+ Misses 832 830 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
4c3aa8f to
a8b419f
Compare
Add an `enforce_feature_owners` boolean on the Project model. When enabled, feature creation requires at least one user or group owner. The owners/group_owners fields on CreateFeatureSerializer are now asymmetric PrimaryKeyRelatedFields (accept IDs on write, return nested objects on read). The remove-owners and remove-group-owners endpoints also prevent removing the last owner when enforcement is on. Frontend adds the project setting toggle, a FeatureOwnerSelect component for the creation modal, create-button validation, and owner chips in the feature modal header.
f9b43dc to
ca55b0d
Compare
…ture_owners - Switch all new tests from deprecated admin_client_original to admin_client_new so they run as both user and master API key - Extract enforcement check into private method
for more information, see https://pre-commit.ci
Merge extra __ segments into the condition part to satisfy the
FT003 lint rule: test_{subject}__{condition}__{expected}.
Already covered by admin_client_new parametrisation on test_create_feature__enforce_owners_enabled_no_owners__returns_400.
Already covered by existing test_remove_owners__specified_owner__removes_only_specified.
There was a problem hiding this comment.
Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.
Once credits are available, reopen this pull request to trigger a review.
Docker builds report
|
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
|
Zaimwa9
left a comment
There was a problem hiding this comment.
Overall good and well working. Couple of comments:
- One refactor sorry but that's part of becoming a frontend 😅
- Couple of questions regarding new UI elements (to be hidden or not depending on the config)
- One backend NIT
Otherwise good job
| if owners: | ||
| instance.owners.add(*owners) |
There was a problem hiding this comment.
On the above (L270), maybe we should skip adding the user as an owner if owners is passed in?
Or NIT: removing it from the owners object?
There was a problem hiding this comment.
Done — if owners is explicitly provided, we now skip the auto-add of the creating user. The elif in create() only auto-adds when no explicit owners are passed.
| @@ -0,0 +1,154 @@ | |||
| import React, { FC, useState } from 'react' | |||
There was a problem hiding this comment.
So actually, this component is great. But we have 2 very similar implementations of assigning users/groups (with the one in settings that has the icon).
It's a small refactor that should be straightforward but let me know if that feels creeping out of scope. It would do a lot of good as moving towards Functional Components and RTK.
The main difference is the old components call the API, your new components trigger a state update. So we should be able to let the parent deal with it and have the components with selectedIds / onAdd / onRemove props
I'd say:
- We get rid of this component sorry
- We migrate
FlagOwnerGroups.js=>FlagOwnerGroups.tsxturning it into a Functional Component so we get rid ofOrganisationProvider(old store) and useuseGetGroupSummariesQueryto get the groups - We migrate
FlagOwners.js=>FlagOwners.tsxturning it into a Functional Component so we get rid ofOrganisationProvider(old store) and useuseGetUsersQueryto get the users - For the create part here we pass in the state setter
- For the update we pass in directly a callback with the API call (with RTK instead of
data.post)
That'd be the best opportunity to do this but I understand if it's too much to ask
There was a problem hiding this comment.
I wanted to suggest to add the icon here to make it more obvious that you can add the user and it led me to look into the existing components
There was a problem hiding this comment.
Done — migrated both FlagOwners.js → FlagOwners.tsx and FlagOwnerGroups.js → FlagOwnerGroups.tsx as functional components using useGetUsersQuery / useGetGroupSummariesQuery (RTK Query). Both support dual mode via discriminated union props:
- Edit mode (
id+projectId): manages internal state, callsdata.postfor add/remove - Create mode (
selectedIds+onAdd/onRemove): purely controlled by parent
Deleted FeatureOwnerSelect.tsx — no longer needed.
| key={chip.id} | ||
| title={<span className='chip chip--xs'>{chip.label}</span>} | ||
| > | ||
| {chip.label} |
There was a problem hiding this comment.
Maybe replace with the email ? Or just keep the chip and remove the tooltip ?
There was a problem hiding this comment.
Done — removed the tooltips, just plain chips now.
| > | ||
| <Icon name='copy' /> | ||
| </Button> | ||
| {ownerChips.length > 0 && ( |
There was a problem hiding this comment.
To align with the team:
- This is new and visible for every feature now no matter the new config enabled or not. Do we want it?
- Same question for the assigned users/groups: they became part of the create form with or without the new config. Is it something we want to introduce or hide ?
There was a problem hiding this comment.
Good call — both the owner chips in the header and the owner picker in the create form are now gated on project.enforce_feature_owners. They only show when the setting is enabled. The edit-mode FlagOwners/FlagOwnerGroups in the settings tab still always show (unchanged behaviour).
| owners?: number[] | ||
| group_owners?: number[] |
There was a problem hiding this comment.
We can directly add them to ProjectFlag then
There was a problem hiding this comment.
Looked into this — ProjectFlag.owners is typed as User[] (nested objects from the API response), but on create we send number[] (IDs). Moving the number[] into ProjectFlag would conflict with the existing User[] field. The intersection type ProjectFlag & { owners?: number[] } correctly represents this asymmetry, so kept as-is.
- Migrate FlagOwners.js and FlagOwnerGroups.js to functional TSX components with RTK Query, supporting dual mode (edit via API, create via parent callbacks) - Delete FeatureOwnerSelect.tsx (replaced by refactored components) - Remove tooltips from modal header owner chips - Gate owner chips and create-form picker on enforce_feature_owners
Thanks for submitting a PR! Please check the boxes below:
docs/if required so people know about the feature.Changes
Closes #4432
Add a project-level
enforce_feature_ownerssetting. When enabled:owners/group_ownersfields on the create serialiser now accept IDs on write and return nested objects on read (asymmetric PrimaryKeyRelatedField — no API contract break)How did you test this code?