Skip to content

Conversation

@anuruddhal
Copy link
Member

@anuruddhal anuruddhal commented Dec 12, 2025

Purpose

Summary by CodeRabbit

  • New Features

    • Added user-store detection API and client method; group selector updated to use this to adjust group visibility.
  • Bug Fixes

    • Prevented undefined errors in API/resource details by defaulting missing lists and normalizing node data parsing.
  • Style

    • Standardized code formatting and spacing across backend and frontend files.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

Walkthrough

Adds backend and frontend support to detect whether a JDBC user store is configured, exposes a new backend endpoint, wires a new HTTP client call, updates group visibility logic in the UI, and includes minor defensive and whitespace-only edits elsewhere.

Changes

Cohort / File(s) Summary
Backend: new endpoint & delegate
components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/rest/api/ConfigsApi.java, components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/rest/delegates/configs/ConfigsDelegate.java
Added isJdbcUserStoreConfigured() API endpoint and delegate method that checks realm configuration / user store class to determine if JDBC user store is configured.
Backend: formatting-only
components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/data/manager/InMemoryDataManager.java
Cosmetic whitespace and formatting normalization (try/catch, for-each spacing, log concatenation); no behavior changes.
Frontend: HTTP client
components/org.wso2.micro.integrator.dashboard.web/web-app/src/utils/HTTPClient.js
Added isJdbcUserStoreConfigured() method; normalized parameter defaults/spacing in several methods (e.g., get(path, params = {})).
Frontend: group selection logic
components/org.wso2.micro.integrator.dashboard.web/web-app/src/home/GroupSelector.js
Fetches JDBC user store flag in parallel with groups, stores isJdbcUserStore, filters/controls visibility of ICP_NAME group based on route and flag, and normalizes node details.
Frontend: defensive UI updates
components/org.wso2.micro.integrator.dashboard.web/web-app/src/commons/sideDrawers/ApiSideDrawer.js
Defaulted possibly-missing arrays (e.g., urlList, resources) to empty arrays before iterating to avoid undefined errors.

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as GroupSelector (UI)
    participant HTTP as HTTPClient
    participant API as ConfigsApi (Backend)
    participant Delegate as ConfigsDelegate
    participant USM as Realm / UserStore

    User->>UI: Open dashboard / GroupSelector mounts
    UI->>HTTP: isJdbcUserStoreConfigured()
    HTTP->>API: GET /configs/isJdbcUserStoreConfigured
    API->>Delegate: isJdbcUserStoreConfigured()
    Delegate->>USM: Load realm configuration / userStoreClass
    alt realm indicates JDBCUserStoreManager
        Delegate-->>API: true
    else not JDBC (file/external)
        Delegate-->>API: false
    end
    API-->>HTTP: { "isJdbcUserStore": boolean }
    HTTP-->>UI: boolean
    UI->>UI: set isJdbcUserStore state
    UI->>UI: filter groups (hide or show ICP_NAME based on flag & route)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to ConfigsDelegate.isJdbcUserStoreConfigured(): realm loading, initialization fallback, and class-name comparison.
  • Verify API response shape matches HTTPClient usage and error handling paths.
  • Review GroupSelector effects and filtering logic to ensure ICP_NAME visibility behaves correctly across routes and state changes.

Poem

🐰 I hopped through code with bright delight,
Checked the store by day and night.
If JDBC's true, I give a cheer,
If not, ICP stays out of here.
Arrays guarded — no more fright!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description provides purpose and linked issue but lacks details on goals, approach, release notes, testing, and other template sections required for a complete PR description. Expand description to include Goals, Approach, Release note, Documentation, User stories, Testing details, and other required template sections to meet repository standards.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Out of Scope Changes check ❓ Inconclusive Most changes are in-scope, but some include minor formatting adjustments (spacing in imports, parameter lists, log statements) that go beyond the core JDBC userstore visibility feature. Clarify whether formatting changes in HTTPClient.js, InMemoryDataManager.java, and ConfigsApi.java are intentional refactoring or incidental; consider separating formatting changes from functional changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly addresses the main objective of the PR: displaying the Integration Control Plane group ID only for JDBC userstore configurations.
Linked Issues check ✅ Passed The code changes implement the primary objective from issue #227 by detecting JDBC userstore configuration and conditionally displaying the ICP group ID only when appropriate, addressing the unwanted extra group ID visibility.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

Comment on lines 108 to 110
}

return groupList;

Choose a reason for hiding this comment

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

Log Improvement Suggestion No: 2

Suggested change
}
return groupList;
}
logger.info("Successfully fetched {} groups", groupList.size());
return groupList;

Comment on lines 50 to 51
public Response getSuperAdmin() {
ConfigsDelegate configsDelegate = new ConfigsDelegate();

Choose a reason for hiding this comment

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

Log Improvement Suggestion No: 3

Suggested change
public Response getSuperAdmin() {
ConfigsDelegate configsDelegate = new ConfigsDelegate();
public Response getSuperAdmin() {
log.info("Retrieving super admin configuration");
ConfigsDelegate configsDelegate = new ConfigsDelegate();

Comment on lines +65 to +66
public Response isJdbcUserStoreConfigured() {
ConfigsDelegate configsDelegate = new ConfigsDelegate();

Choose a reason for hiding this comment

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

Log Improvement Suggestion No: 4

Suggested change
public Response isJdbcUserStoreConfigured() {
ConfigsDelegate configsDelegate = new ConfigsDelegate();
public Response isJdbcUserStoreConfigured() {
log.info("Checking JDBC user store configuration");
ConfigsDelegate configsDelegate = new ConfigsDelegate();

Comment on lines +45 to +46
public boolean isJdbcUserStoreConfigured() {
log.debug("Checking if JDBC user store is configured.");

Choose a reason for hiding this comment

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

Log Improvement Suggestion No: 5

Suggested change
public boolean isJdbcUserStoreConfigured() {
log.debug("Checking if JDBC user store is configured.");
public boolean isJdbcUserStoreConfigured() {
log.info("Checking if JDBC user store is configured");
log.debug("Checking if JDBC user store is configured.");

String userStoreClass = realmConfig.getUserStoreClass();
boolean isJdbc = "org.wso2.dashboard.security.user.core.jdbc.JDBCUserStoreManager"
.equals(userStoreClass);
log.info("User store class: " + userStoreClass + ", is JDBC: " + isJdbc);

Choose a reason for hiding this comment

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

Log Improvement Suggestion No: 6

Suggested change
log.info("User store class: " + userStoreClass + ", is JDBC: " + isJdbc);
log.info("User store class: " + userStoreClass + ", is JDBC: " + isJdbc);
if (log.isDebugEnabled()) {
log.debug("Determined user store type - Class: " + userStoreClass + ", is JDBC: " + isJdbc);
}

Copy link

@wso2-engineering wso2-engineering bot left a comment

Choose a reason for hiding this comment

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

AI Agent Log Improvement Checklist

⚠️ Warning: AI-Generated Review Comments

  • The log-related comments and suggestions in this review were generated by an AI tool to assist with identifying potential improvements. Purpose of reviewing the code for log improvements is to improve the troubleshooting capabilities of our products.
  • Please make sure to manually review and validate all suggestions before applying any changes. Not every code suggestion would make sense or add value to our purpose. Therefore, you have the freedom to decide which of the suggestions are helpful.

✅ Before merging this pull request:

  • Review all AI-generated comments for accuracy and relevance.
  • Complete and verify the table below. We need your feedback to measure the accuracy of these suggestions and the value they add. If you are rejecting a certain code suggestion, please mention the reason briefly in the suggestion for us to capture it.
Comment Accepted (Y/N) Reason
#### Log Improvement Suggestion No: 2
#### Log Improvement Suggestion No: 3
#### Log Improvement Suggestion No: 4
#### Log Improvement Suggestion No: 5
#### Log Improvement Suggestion No: 6

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 (6)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/commons/sideDrawers/ApiSideDrawer.js (3)

77-77: Good defensive default for urlList.

The empty array default prevents runtime errors when urlList is missing, which aligns with addressing the blank page issue mentioned in Issue #227.

Note: The truthiness check on line 92 (urls && urls.map) is now redundant since urls is guaranteed to be an array. You may optionally simplify it to just urls.map(url =>.


92-94: Consider adding key prop to mapped elements.

The .map() call is missing a key prop on the rendered CopyToClipboardRow components, which can trigger React warnings.

Apply this diff to add the key prop:

-                    {urls && urls.map(url =>
-                        <CopyToClipboardRow text={url} />
+                    {urls.map((url, index) =>
+                        <CopyToClipboardRow key={index} text={url} />
                     )}

108-127: Consider adding key prop to mapped ExpansionPanel components.

The .map() call is missing a key prop on the rendered ExpansionPanel components.

Apply this diff to add the key prop:

-    return (resources.map(resource => (
-        <ExpansionPanel>
+    return (resources.map((resource, index) => (
+        <ExpansionPanel key={resource.url || index}>
             <ExpansionPanelSummary

Note: Using resource.url as the key assumes URLs are unique; otherwise, fall back to index.

components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/rest/api/ConfigsApi.java (1)

57-71: Prefer proper JSON serialization over manual string construction.

Line 68 manually constructs the JSON response as a string. This approach is error-prone and bypasses type safety. Consider creating a dedicated response model class and using JAX-RS's automatic JSON serialization.

Create a response model:

public class JdbcUserStoreResponse {
    private boolean isJdbcUserStore;
    
    public JdbcUserStoreResponse(boolean isJdbcUserStore) {
        this.isJdbcUserStore = isJdbcUserStore;
    }
    
    public boolean isJdbcUserStore() {
        return isJdbcUserStore;
    }
    
    public void setJdbcUserStore(boolean jdbcUserStore) {
        isJdbcUserStore = jdbcUserStore;
    }
}

Then update the endpoint:

 public Response isJdbcUserStoreConfigured() {
     ConfigsDelegate configsDelegate = new ConfigsDelegate();
     boolean isJdbc = configsDelegate.isJdbcUserStoreConfigured();
-    Response.ResponseBuilder responseBuilder = Response.ok().entity("{\"isJdbcUserStore\": " + isJdbc + "}");
+    Response.ResponseBuilder responseBuilder = Response.ok().entity(new JdbcUserStoreResponse(isJdbc));
     HttpUtils.setHeaders(responseBuilder);
     return responseBuilder.build();
 }
components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/rest/delegates/configs/ConfigsDelegate.java (1)

45-74: Consider extracting the hardcoded JDBC class name and improving error handling.

The implementation has two areas for improvement:

  1. Hardcoded class name (lines 62-63): The JDBC user store class name is hardcoded. Extract it to a constant for maintainability.

  2. Generic exception handling (line 70): Catching generic Exception can mask important errors. Consider catching specific exceptions or at least logging more details about unexpected errors.

Apply this diff:

 public class ConfigsDelegate {
     private static final Log log = LogFactory.getLog(ConfigsDelegate.class);
+    private static final String JDBC_USER_STORE_CLASS = "org.wso2.dashboard.security.user.core.jdbc.JDBCUserStoreManager";

     public SuperAdminUser getSuperUser() {
         log.debug("Retrieving super user from system properties.");
         SuperAdminUser superAdminUser = new SuperAdminUser();
         String superAdminUserName = (String) ConfigParser.getParsedConfigs().get("super_admin.username");
         superAdminUser.setUsername(superAdminUserName);
         return superAdminUser;
     }

     public boolean isJdbcUserStoreConfigured() {
         log.debug("Checking if JDBC user store is configured.");
         try {
             if (UserStoreManagerUtils.isFileBasedUserStoreEnabled()) {
                 log.debug("File-based user store is enabled. JDBC user store is not configured.");
                 return false;
             }

             RealmConfiguration realmConfig = DataHolder.getInstance().getRealmConfig();
             if (realmConfig == null) {
                 // Try to initialize user store to get realm config
                 UserStoreManagerUtils.getUserStoreManager();
                 realmConfig = DataHolder.getInstance().getRealmConfig();
             }

             if (realmConfig != null) {
                 String userStoreClass = realmConfig.getUserStoreClass();
-                boolean isJdbc = "org.wso2.dashboard.security.user.core.jdbc.JDBCUserStoreManager"
-                        .equals(userStoreClass);
+                boolean isJdbc = JDBC_USER_STORE_CLASS.equals(userStoreClass);
                 log.info("User store class: " + userStoreClass + ", is JDBC: " + isJdbc);
                 return isJdbc;
             }

             log.debug("Realm configuration is null. JDBC user store is not configured.");
             return false
         } catch (Exception e) {
-            log.error("Error while checking JDBC user store configuration", e);
+            log.error("Unexpected error while checking JDBC user store configuration. Defaulting to non-JDBC.", e);
             return false;
         }
     }
 }
components/org.wso2.micro.integrator.dashboard.web/web-app/src/home/GroupSelector.js (1)

67-72: Add error handling for JSON.parse.

Line 69 parses node.details without error handling. If the details field contains invalid JSON, this will throw an exception and break the UI.

Apply this diff:

 function loadNodesForGroup(group, dispatch) {
   HTTPClient.getAllNodes(group).then(response => {
-    response.data = response.data.map(node => ({ ...node, details: JSON.parse(node.details) }));
+    response.data = response.data.map(node => {
+      try {
+        return { ...node, details: JSON.parse(node.details) };
+      } catch (e) {
+        console.error(`Failed to parse node details for node ${node.nodeId}:`, e);
+        return { ...node, details: {} };
+      }
+    });
     dispatch(selectGroup(group, response.data));
   })
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da21bea and d076713.

📒 Files selected for processing (6)
  • components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/data/manager/InMemoryDataManager.java (11 hunks)
  • components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/rest/api/ConfigsApi.java (1 hunks)
  • components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/rest/delegates/configs/ConfigsDelegate.java (2 hunks)
  • components/org.wso2.micro.integrator.dashboard.web/web-app/src/commons/sideDrawers/ApiSideDrawer.js (2 hunks)
  • components/org.wso2.micro.integrator.dashboard.web/web-app/src/home/GroupSelector.js (1 hunks)
  • components/org.wso2.micro.integrator.dashboard.web/web-app/src/utils/HTTPClient.js (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/commons/sideDrawers/ApiSideDrawer.js (2)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/commons/sideDrawers/DataServicesSideDrawer.js (2)
  • nodeData (69-69)
  • resources (189-189)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/commons/sideDrawers/ProxySideDrawer.js (2)
  • props (36-36)
  • props (62-62)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/home/GroupSelector.js (2)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/utils/HTTPClient.js (1)
  • HTTPClient (25-237)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/redux/Actions.js (4)
  • changeGroup (19-24)
  • changeGroup (19-24)
  • selectGroup (62-67)
  • selectGroup (62-67)
components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/rest/delegates/configs/ConfigsDelegate.java (1)
components/org.wso2.dashboard.security.user.core/src/main/java/org/wso2/dashboard/security/user/core/UserStoreManagerUtils.java (1)
  • UserStoreManagerUtils (37-101)
🪛 Biome (2.1.2)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/home/GroupSelector.js

[error] 119-119: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

🔇 Additional comments (7)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/commons/sideDrawers/ApiSideDrawer.js (1)

107-108: Good defensive default for resources.

The empty array default and direct map iteration are clean and prevent runtime errors when resources is missing.

components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/data/manager/InMemoryDataManager.java (1)

73-73: LGTM! Formatting improvements.

The whitespace and formatting changes improve code readability without altering behavior.

Also applies to: 90-90, 94-94, 103-103, 109-109, 120-120, 139-139, 158-158, 175-175, 182-182, 188-188, 195-195, 200-200, 226-226, 240-240, 254-254, 266-266

components/org.wso2.ei.dashboard.core/src/main/java/org/wso2/ei/dashboard/core/rest/api/ConfigsApi.java (1)

45-55: LGTM! Formatting improvements.

The formatting adjustments improve readability without changing behavior.

components/org.wso2.micro.integrator.dashboard.web/web-app/src/utils/HTTPClient.js (4)

23-23: LGTM! Import formatting improved.

The spacing adjustment improves consistency.


45-47: LGTM! Good defensive programming.

Adding a default empty object for the params parameter prevents potential issues when the method is called without the second argument.


74-76: LGTM! New method follows established patterns.

The isJdbcUserStoreConfigured() method correctly uses the get() method to call the backend endpoint and follows the same pattern as other methods in this class.


100-100: LGTM! Formatting improvements.

The spacing and formatting adjustments improve code consistency and readability.

Also applies to: 136-136, 177-180, 182-185, 189-198, 215-218

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: 3

🧹 Nitpick comments (1)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/home/GroupSelector.js (1)

21-63: Nice fix for the async “who wins first” issue; consider stale-route + unmount safety.
The Promise.all sequencing is good (and addresses the earlier race), but this effect reads location.pathname while the requests are in-flight (Line 45-47). If the user navigates before the promises resolve, you can filter/select using a stale route and dispatch the wrong initial group. Also, there’s no unmount guard before setIsJdbcUserStore / setGroupList.

 React.useEffect(() => {
-  // Wait for both JDBC user store check and groups to load before selecting initial group
+  let cancelled = false;
   Promise.all([
     HTTPClient.isJdbcUserStoreConfigured().catch(error => {
       console.error("Error checking external user store configuration:", error);
       return { data: { isJdbcUserStore: false } };
     }),
     HTTPClient.getGroups()
   ]).then(([userStoreResponse, groupsResponse]) => {
+    if (cancelled) return;
     // Set JDBC user store flag first
     const jdbcUserStore = userStoreResponse.data.isJdbcUserStore;
     setIsJdbcUserStore(jdbcUserStore);
+    const pathname = window.location.pathname; // avoid stale route
 
     // Filter groups based on current location and JDBC user store status
-    const shouldShowICP = (location.pathname.startsWith("/users") ||
-      location.pathname.startsWith("/roles") ||
-      location.pathname.startsWith("/update-password")) && jdbcUserStore;
+    const shouldShowICP = (pathname.startsWith("/users") ||
+      pathname.startsWith("/roles") ||
+      pathname.startsWith("/update-password")) && jdbcUserStore;
     ...
   }).catch(error => {
     console.error("Error loading groups:", error);
   });
-}, [])
+  return () => { cancelled = true; };
+}, []);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d076713 and ee25893.

📒 Files selected for processing (1)
  • components/org.wso2.micro.integrator.dashboard.web/web-app/src/home/GroupSelector.js (1 hunks)
🔇 Additional comments (1)
components/org.wso2.micro.integrator.dashboard.web/web-app/src/home/GroupSelector.js (1)

146-151: Style change looks fine (minHeight/lineHeight pairing).
No concerns here.

@anuruddhal anuruddhal merged commit cbd15f7 into wso2:main Dec 12, 2025
10 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UI-Related Concerns Observed with ICP 1.2

2 participants