[Frontend] Create API-only users that only have access to customer-defined Fleet API endpoints #43281
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #43281 +/- ##
==========================================
- Coverage 66.91% 66.84% -0.08%
==========================================
Files 2600 2589 -11
Lines 208710 207177 -1533
Branches 9302 9172 -130
==========================================
- Hits 139666 138481 -1185
+ Misses 56327 56095 -232
+ Partials 12717 12601 -116
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@frontend/pages/admin/UserManagementPage/components/ApiUserForm/ApiUserForm.tsx`:
- Line 245: The submit button is being disabled based on combinedErrors (which
merges local formErrors and server/prop ancestorErrors) so server-provided
ancestorErrors can keep the button disabled after the user fixes local inputs;
change the disabled logic to only consider the component-controlled local
validation state (formErrors) or otherwise exclude ancestorErrors from the
disabling condition: update the disabled prop to use
Object.keys(formErrors).length > 0 (or compute a new localOnlyErrors from
formErrors) while still displaying combinedErrors to the user; reference
combinedErrors, formErrors, and ancestorErrors to locate and adjust the check.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 685c3bac-fe82-42b3-a64e-4d09de160b43
📒 Files selected for processing (1)
frontend/pages/admin/UserManagementPage/components/ApiUserForm/ApiUserForm.tsx
There was a problem hiding this comment.
🧹 Nitpick comments (1)
frontend/pages/admin/UserManagementPage/_styles.scss (1)
199-247: Consider extracting repeated values for maintainability.Minor observations:
- The
top: 44pxon line 202 is a magic number likely tied to the search input height. If that input's height changes, this will need manual adjustment.- The
box-shadowvalue0px 4px 10px rgba(52, 59, 96, 0.15)is duplicated on lines 209 and 229.These could be extracted to variables or a mixin for easier maintenance, but not critical for this PR.
♻️ Optional: Extract duplicated shadow to a variable
+// At top of file or in variables partial +$dropdown-shadow: 0px 4px 10px rgba(52, 59, 96, 0.15); &__search-dropdown { // ... .table-container { - box-shadow: 0px 4px 10px rgba(52, 59, 96, 0.15); + box-shadow: $dropdown-shadow; // ... } .empty-search { // ... - box-shadow: 0px 4px 10px rgba(52, 59, 96, 0.15); + box-shadow: $dropdown-shadow; } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/pages/admin/UserManagementPage/_styles.scss` around lines 199 - 247, The CSS in the &__search-dropdown block uses a magic number top: 44px and repeats the box-shadow value in .table-container and .empty-search; extract these into SCSS variables or a mixin (e.g., $search-input-height or $search-dropdown-top and $card-box-shadow) and replace the hardcoded top: 44px and both box-shadow declarations in the &__search-dropdown > .table-container and &__search-dropdown > .empty-search to reference the new variables/mixin (locate the selectors &__search-dropdown, .table-container, and .empty-search in the diff).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@frontend/pages/admin/UserManagementPage/_styles.scss`:
- Around line 199-247: The CSS in the &__search-dropdown block uses a magic
number top: 44px and repeats the box-shadow value in .table-container and
.empty-search; extract these into SCSS variables or a mixin (e.g.,
$search-input-height or $search-dropdown-top and $card-box-shadow) and replace
the hardcoded top: 44px and both box-shadow declarations in the
&__search-dropdown > .table-container and &__search-dropdown > .empty-search to
reference the new variables/mixin (locate the selectors &__search-dropdown,
.table-container, and .empty-search in the diff).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: df89b295-a85e-4aee-9012-29f265ed7ea8
📒 Files selected for processing (1)
frontend/pages/admin/UserManagementPage/_styles.scss
| return ( | ||
| <div className={baseClass}> | ||
| <div className={`${baseClass}__api-key-label`}> | ||
| <b>API key</b> |
There was a problem hiding this comment.
nit: Figma shows API Key
| Cell: NameCell, | ||
| }, | ||
| { | ||
| title: "Protocol", |
There was a problem hiding this comment.
This should be "Method"
| const searchResults: IEndpointRow[] = useMemo(() => { | ||
| if (isEmpty(searchText)) return []; | ||
| const query = searchText.toLowerCase(); | ||
| return allRows.filter( |
There was a problem hiding this comment.
This search functionality needs to align with this: https://github.com/fleetdm/fleet/pull/42352/changes#diff-7246bc304b15c8865ed8eaa205e9c244d0a0314e4bae60cf553dc06147c38b64R13916
| const { USERS_API_ONLY } = endpoints; | ||
|
|
||
| return sendRequest("POST", USERS_API_ONLY, formData).then((response) => ({ | ||
| user: helpers.addGravatarUrlToResource(response.user), |
There was a problem hiding this comment.
calling helpers.addGravatarUrlToResource shouldn't be necessary here - API only users don't have a gravatar
| const path = `${USERS_API_ONLY}/${userId}`; | ||
|
|
||
| return sendRequest("PATCH", path, formData).then((response) => | ||
| helpers.addGravatarUrlToResource(response.user) |
There was a problem hiding this comment.
See prev comment, calling addGravatarUrlToResource is not needed
* Show error if token could not be retrieved on API user creation. * Inject isPremiumTier from parent component. * Cleaned up imports. * Renamed components for better intent. * Use IApiEndpointRef type instead of plain string.

Related issue: Resolves #42879
Checklist for submitter
changes/,orbit/changes/oree/fleetd-chrome/changes.See Changes files for more information.
Testing
Tested with latest backend changes from: #43440
Regular user create/edit
regularuser.mov
API-only user create/edit
apionly_1.mov
API-only user form validation
Screen.Recording.2026-04-15.at.3.48.37.PM.mov
Summary by CodeRabbit
New Features
Improvements
Minor