Skip to content

feat: (UI) Hide User/Profile API Key Features in UI if depending on parameter value BED-7137#2418

Open
Useinovski wants to merge 13 commits intomainfrom
BED-7137
Open

feat: (UI) Hide User/Profile API Key Features in UI if depending on parameter value BED-7137#2418
Useinovski wants to merge 13 commits intomainfrom
BED-7137

Conversation

@Useinovski
Copy link
Contributor

@Useinovski Useinovski commented Feb 25, 2026

Description

This change was to remove the buttons that manage api tokens in the "Manage Users" page as well as the "Profile" page depending on the config flag.

Motivation and Context

Resolves BED-7137

How Has This Been Tested?

Tested locally by flipping the value in the parameter table between true/false.

Screenshots (optional):

Screenshot 2026-02-25 at 11 41 53 AM Screenshot 2026-02-25 at 11 42 05 AM

Types of changes

  • Chore (a change that does not modify the application functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Database Migrations

Checklist:

Summary by CodeRabbit

  • New Features

    • API token management features, including API Key Management and token generation/revocation options, are now controlled by server configuration and will display or hide accordingly.
  • Tests

    • Added comprehensive tests to verify API token management features correctly display when enabled and properly hide when disabled via server configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

This PR adds conditional rendering of API token management features throughout the UI based on configuration settings. It includes a new noop utility function, updates to two components that conditionally display API token features, and comprehensive test coverage with mocked configuration endpoints.

Changes

Cohort / File(s) Summary
Utility Addition
packages/javascript/bh-shared-ui/src/utils/object.ts
Added noop function that returns undefined.
UserProfile Component
packages/javascript/bh-shared-ui/src/views/UserProfile/UserProfile.tsx, packages/javascript/bh-shared-ui/src/views/UserProfile/UserProfile.test.tsx
Conditionally renders "API Key Management" section based on useAPITokensConfiguration hook result; includes tests with mocked config endpoint verifying visibility toggle.
UserActionsMenu Component
packages/javascript/bh-shared-ui/src/views/Users/UserActionsMenu.tsx, packages/javascript/bh-shared-ui/src/views/Users/UserActionsMenu.test.tsx
Conditionally renders "Generate / Revoke API Tokens" menu item based on configuration; includes comprehensive tests with MSW mock server setup for both enabled and disabled config scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

user interface, enhancement

Suggested reviewers

  • specter-flq
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: hiding API Key features in the UI based on a configuration parameter across User/Profile pages, with the associated ticket reference.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The pull request description includes all required sections: a clear description of changes, motivation/context with ticket reference (BED-7137), testing details, screenshots, and a completed checklist.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch BED-7137

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai bot added enhancement New feature or request user interface A pull request containing changes affecting the UI code. labels Feb 25, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/javascript/bh-shared-ui/src/utils/object.ts (1)

20-20: Consider avoiding runtime API-surface expansion for noop.

If this helper is only for test setup, keep it in test utilities instead of exporting it from shared runtime utils to reduce long-term public API maintenance.

Based on learnings: "Avoid exporting internal, implementation-only modules that aren’t meant for external consumption; document and surface stable APIs for downstream users."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/javascript/bh-shared-ui/src/utils/object.ts` at line 20, The
exported runtime helper noop is expanding the public API surface; remove the
export from packages/javascript/bh-shared-ui/src/utils/object.ts (stop exporting
or delete the noop constant) and move it into your test utilities (e.g., a
tests/utils or __tests__/helpers file) so only test code imports it; update any
modules that currently import noop to instead import the new test-only helper,
or replace usages with inline no-op functions where appropriate, ensuring noop
is no longer part of the shared runtime exports.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/javascript/bh-shared-ui/src/views/UserProfile/UserProfile.test.tsx`:
- Around line 212-217: The test asserts the "API Key Management" button is
absent before the async configuration query settles; update the test around
QueryClient, UserProfile and configurationKeys.all to wait for the config query
to finish (e.g., use testing-library's waitFor or waitForElementToBeRemoved) and
then assert that screen.queryByRole('button', { name: 'API Key Management' }) is
not in the document; ensure the wait targets a stable indicator of query
completion (like waiting for QueryClient to stop fetching or for a known loading
indicator to disappear) before making the non-presence assertion.

In `@packages/javascript/bh-shared-ui/src/views/Users/UserActionsMenu.test.tsx`:
- Around line 112-124: The test "should not display generate/revoke api tokens
button" races with the async /api/v2/config response; make the assertion
deterministic by awaiting the config fetch completion before checking for the
menu item. Update the test in UserActionsMenu.test.tsx (the it block with name
'should not display generate/revoke api tokens button') to wait for the
fetch—e.g. await screen.findBy... for an element rendered after config loads or
wrap the assertion in await waitFor(() => expect(screen.queryByRole('menuitem',
{ name: /generate \/ revoke api tokens/i })).not.toBeInTheDocument())—so the
query runs only after the mocked /api/v2/config handler has resolved.

---

Nitpick comments:
In `@packages/javascript/bh-shared-ui/src/utils/object.ts`:
- Line 20: The exported runtime helper noop is expanding the public API surface;
remove the export from packages/javascript/bh-shared-ui/src/utils/object.ts
(stop exporting or delete the noop constant) and move it into your test
utilities (e.g., a tests/utils or __tests__/helpers file) so only test code
imports it; update any modules that currently import noop to instead import the
new test-only helper, or replace usages with inline no-op functions where
appropriate, ensuring noop is no longer part of the shared runtime exports.

ℹ️ Review info

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e80426f and e2390e8.

📒 Files selected for processing (5)
  • packages/javascript/bh-shared-ui/src/utils/object.ts
  • packages/javascript/bh-shared-ui/src/views/UserProfile/UserProfile.test.tsx
  • packages/javascript/bh-shared-ui/src/views/UserProfile/UserProfile.tsx
  • packages/javascript/bh-shared-ui/src/views/Users/UserActionsMenu.test.tsx
  • packages/javascript/bh-shared-ui/src/views/Users/UserActionsMenu.tsx

Comment on lines +212 to +217
const queryClient = new QueryClient();
render(<UserProfile />, { queryClient });

await queryClient.invalidateQueries(configurationKeys.all);
const apiKeyManagementButton = screen.queryByRole('button', { name: 'API Key Management' });
expect(apiKeyManagementButton).not.toBeInTheDocument();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Stabilize the disabled-state assertion to avoid false positives.

At Line 216, absence is asserted immediately; this can pass before the async config query settles. Wait for configuration query completion first, then assert non-presence.

💡 Suggested test hardening
     const queryClient = new QueryClient();
     render(<UserProfile />, { queryClient });

-    await queryClient.invalidateQueries(configurationKeys.all);
-    const apiKeyManagementButton = screen.queryByRole('button', { name: 'API Key Management' });
-    expect(apiKeyManagementButton).not.toBeInTheDocument();
+    await waitFor(() =>
+        expect(queryClient.getQueryState(configurationKeys.all)?.status).toBe('success')
+    );
+    expect(screen.queryByRole('button', { name: 'API Key Management' })).not.toBeInTheDocument();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const queryClient = new QueryClient();
render(<UserProfile />, { queryClient });
await queryClient.invalidateQueries(configurationKeys.all);
const apiKeyManagementButton = screen.queryByRole('button', { name: 'API Key Management' });
expect(apiKeyManagementButton).not.toBeInTheDocument();
const queryClient = new QueryClient();
render(<UserProfile />, { queryClient });
await waitFor(() =>
expect(queryClient.getQueryState(configurationKeys.all)?.status).toBe('success')
);
expect(screen.queryByRole('button', { name: 'API Key Management' })).not.toBeInTheDocument();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/javascript/bh-shared-ui/src/views/UserProfile/UserProfile.test.tsx`
around lines 212 - 217, The test asserts the "API Key Management" button is
absent before the async configuration query settles; update the test around
QueryClient, UserProfile and configurationKeys.all to wait for the config query
to finish (e.g., use testing-library's waitFor or waitForElementToBeRemoved) and
then assert that screen.queryByRole('button', { name: 'API Key Management' }) is
not in the document; ensure the wait targets a stable indicator of query
completion (like waiting for QueryClient to stop fetching or for a known loading
indicator to disappear) before making the non-presence assertion.

Comment on lines +112 to +124
it('should not display generate/revoke api tokens button', async () => {
server.use(
rest.get(`/api/v2/config`, async (_req, res, ctx) => {
return res(ctx.json(CONFIG_DISABLED_RESPONSE));
})
);
const { user } = setup();

const button = screen.getByRole('button', { name: /show user actions/i });
await user.click(button);

const apiKeyManagementButton = screen.queryByRole('menuitem', { name: /generate \/ revoke api tokens/i });
expect(apiKeyManagementButton).not.toBeInTheDocument();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make the disabled-path check deterministic after config fetch.

At Line 123, immediate queryByRole can pass before /api/v2/config resolves. Gate the assertion on observing the config request completion.

💡 Suggested test hardening
-import { render, screen } from '../../test-utils';
+import { render, screen, waitFor } from '../../test-utils';

 it('should not display generate/revoke api tokens button', async () => {
+    let configRequested = false;
     server.use(
         rest.get(`/api/v2/config`, async (_req, res, ctx) => {
+            configRequested = true;
             return res(ctx.json(CONFIG_DISABLED_RESPONSE));
         })
     );
     const { user } = setup();

     const button = screen.getByRole('button', { name: /show user actions/i });
     await user.click(button);

+    await waitFor(() => expect(configRequested).toBe(true));
     const apiKeyManagementButton = screen.queryByRole('menuitem', { name: /generate \/ revoke api tokens/i });
     expect(apiKeyManagementButton).not.toBeInTheDocument();
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('should not display generate/revoke api tokens button', async () => {
server.use(
rest.get(`/api/v2/config`, async (_req, res, ctx) => {
return res(ctx.json(CONFIG_DISABLED_RESPONSE));
})
);
const { user } = setup();
const button = screen.getByRole('button', { name: /show user actions/i });
await user.click(button);
const apiKeyManagementButton = screen.queryByRole('menuitem', { name: /generate \/ revoke api tokens/i });
expect(apiKeyManagementButton).not.toBeInTheDocument();
import { render, screen, waitFor } from '../../test-utils';
it('should not display generate/revoke api tokens button', async () => {
let configRequested = false;
server.use(
rest.get(`/api/v2/config`, async (_req, res, ctx) => {
configRequested = true;
return res(ctx.json(CONFIG_DISABLED_RESPONSE));
})
);
const { user } = setup();
const button = screen.getByRole('button', { name: /show user actions/i });
await user.click(button);
await waitFor(() => expect(configRequested).toBe(true));
const apiKeyManagementButton = screen.queryByRole('menuitem', { name: /generate \/ revoke api tokens/i });
expect(apiKeyManagementButton).not.toBeInTheDocument();
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/javascript/bh-shared-ui/src/views/Users/UserActionsMenu.test.tsx`
around lines 112 - 124, The test "should not display generate/revoke api tokens
button" races with the async /api/v2/config response; make the assertion
deterministic by awaiting the config fetch completion before checking for the
menu item. Update the test in UserActionsMenu.test.tsx (the it block with name
'should not display generate/revoke api tokens button') to wait for the
fetch—e.g. await screen.findBy... for an element rendered after config loads or
wrap the assertion in await waitFor(() => expect(screen.queryByRole('menuitem',
{ name: /generate \/ revoke api tokens/i })).not.toBeInTheDocument())—so the
query runs only after the mocked /api/v2/config handler has resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request user interface A pull request containing changes affecting the UI code.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants