Skip to content

Conversation

@Iduranga-Uwanpriya
Copy link

@Iduranga-Uwanpriya Iduranga-Uwanpriya commented Oct 31, 2025

Description

Fixes issue #3781 where policy editing controls remain enabled on API revision pages, allowing users to attempt modifications even though revisions are read-only.

Problem Statement

When viewing an API revision in the Publisher portal's Policies page, users can interact with editing controls that should be disabled:

  • "Add New Policy" button is clickable
  • "Save" button is clickable
  • Policy drag-and-drop functionality is enabled
  • Edit and delete actions appear available

This creates a confusing user experience as revisions are immutable snapshots and should not allow any modifications.

Solution

Implemented a comprehensive read-only mode for policy pages when viewing revisions:

  1. Revision Detection: Added logic in Policies.tsx to detect revision views using api.isRevision || Boolean(api.revisionId)

  2. Props Propagation: Created a disabled prop that flows through the component hierarchy to ensure consistent behavior across all policy-related components

  3. UI Control Management: Updated all interactive elements to respect the disabled state while keeping policy information visible

Changes Made

Core Components Modified:

Policies.tsx

  • Added isRevision constant for revision detection
  • Updated context provider to include disabled state
  • Passed disabled prop to child components (PolicyPanel, PolicyList, SaveOperationPolicies)

PolicyPanel.tsx

  • Added disabled prop to interface
  • Forwarded prop to PoliciesSection

PoliciesSection.tsx

  • Added disabled prop to interface
  • Passed prop to PoliciesExpansion (API level) and OperationPolicy (operation level)

PoliciesExpansion.tsx

  • Added disabled prop to interface
  • Updated isApiRevision prop in shared component to include disabled state: isApiRevision={disabled || api.isRevision}

OperationPolicy.tsx

  • Added disabled prop to interface
  • Forwarded prop to nested PoliciesExpansion

PolicyList.tsx

  • Added disabled prop to interface
  • Modified "Add New Policy" button: disabled={disabled || isRestricted([...])}
  • Passed disabled to all TabPanel components (Request, Response, Fault flows)

TabPanel.tsx

  • Added disabled prop to interface
  • Combined with existing isReadOnly prop: isReadOnly={disabled || isReadOnly}

SaveOperationPolicies.tsx

  • Added disabled prop to interface
  • Updated disable condition: disabled || api.isRevision || ...

Technical Implementation Details

Design Pattern

The solution follows React's unidirectional data flow pattern, where the disabled state is determined at the top level (Policies.tsx) and propagates down through props.

Shared Component Integration

The implementation integrates with existing shared components (PoliciesExpansionShared, TabPanelShared) by utilizing their existing isApiRevision and isReadOnly props rather than modifying the shared components themselves.

Backward Compatibility

All new props are optional (disabled?: boolean) with default values, ensuring backward compatibility with existing code.

Testing Performed

Compilation

  • ✅ Frontend compiles successfully without errors
  • ✅ No TypeScript compilation errors
  • ✅ Webpack builds complete successfully

Code Review

  • ✅ All modified components follow consistent patterns
  • ✅ Props properly typed with TypeScript interfaces
  • ✅ Disabled state properly propagated through component tree
  • ✅ Integration with shared components uses existing props

Manual Testing Checklist

Due to local development environment issues, comprehensive manual testing is pending. However, the implementation follows established patterns already present in the codebase (e.g., SaveOperationPolicies already implements revision checking).

Expected Behavior (for reviewer verification):

On Revision Pages:

  • "Add New Policy" button is disabled (grayed out)
  • "Save" button is disabled (grayed out)
  • All existing policies are visible
  • Policies cannot be dragged or reordered
  • Policy edit icons are disabled
  • Policy delete icons are disabled
  • Tabs remain functional for viewing different flows

On Regular API Pages (Non-Revision):

  • All functionality works normally
  • Can add new policies
  • Can edit existing policies
  • Can delete policies
  • Can drag and reorder policies
  • Can save changes

Testing Instructions for Reviewers

Prerequisites

  • WSO2 API Manager 4.4.0+ backend running
  • Publisher portal frontend running on port 8081

Steps to Test

  1. Setup:
   git checkout fix/3781-readonly-policy-tab-v2
   cd portals/publisher/src/main/webapp
   npm ci
   npm start
  1. Create Test API:

    • Login to Publisher (http://localhost:8081/publisher)
    • Create new REST API (Design → Start from Scratch)
    • Name: "Test API", Version: "1.0.0", Context: "/test"
  2. Attach Policies:

    • Navigate to Policies page
    • Drag policies to Request and Response flows
    • Click Save
  3. Create Revision:

    • Navigate to Deployments page
    • Click "Create Revision"
    • Name: "Test Revision 1"
    • Click Create
  4. Verify Read-Only Behavior:

    • Click on "Test Revision 1" to view the revision
    • Navigate to Policies page
    • Verify:
      • "Add New Policy" button is disabled
      • "Save" button is disabled
      • Policies are visible
      • Cannot drag policies
      • Cannot edit/delete policies
  5. Verify Normal API Still Works:

    • Navigate back to main API (breadcrumb or API list)
    • Go to Policies page
    • Verify:
      • "Add New Policy" button is enabled
      • Can drag and drop policies
      • Can edit/delete policies
      • Can save changes

Related Issue

Resolves #3781

Screenshots

Note: Screenshots currently unavailable due to local development environment configuration issues. The code implementation has been completed following established patterns in the codebase.

Checklist

  • Code follows project coding standards
  • Changes compile without errors
  • TypeScript types are properly defined
  • Props are properly propagated through component hierarchy
  • Backward compatibility maintained
  • Integration with shared components uses existing APIs
  • No breaking changes introduced
  • Manual UI testing (pending reviewer verification)

Additional Notes

This implementation maintains the principle of "show the data, disable the actions" - ensuring that policy information remains visible and accessible for reference while preventing any modifications to the immutable revision.

The solution is minimal and focused, touching only the necessary components to achieve the desired functionality without introducing unnecessary complexity or architectural changes.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
5.7% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@tharikaGitHub
Copy link
Member

@Iduranga-Uwanpriya also will you be able to attach screenshots to depict the behaviour introduced by this PR?

@Iduranga-Uwanpriya
Copy link
Author

@Iduranga-Uwanpriya also will you be able to attach screenshots to depict the behaviour introduced by this PR?

Hi @tharikaGitHub ,

When I ran the app for the first time to test it, everything loaded perfectly. However, after some time, I wasn’t able to load the app properly due to the large chunk file size.

I really appreciate all the guidance and references you shared I tried all of them, but unfortunately, even by the end of Hacktoberfest, I couldn’t get it working. I’m also really sorry that I couldn’t provide any screenshots.

But I did test the “Add Policy” and other buttons they don’t seem to work in revision mode, as they’re all grayed out.

Thank you again for all your help and support!

const Policies: React.FC = () => {

const [api, updateAPI] = useAPI();
const isRevision = api.isRevision || Boolean(api.revisionId);
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need a check like this? || Boolean(api.revisionId); Wouldn't api.isRevision be sufficient?

PolicyDropzone={PolicyDropzone}
listOriginatedFromCommonPolicies={listOriginatedFromCommonPolicies}
isApiRevision={api.isRevision}
isApiRevision={disabled || api.isRevision}
Copy link
Member

Choose a reason for hiding this comment

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

Do we need this disabled check when api.isRevision check is already there?

<Grid item>
<Box p={1} mt={3}>
{api.isRevision || (settings && settings.portalConfigurationOnlyModeEnabled) || isRestricted(['apim:api_create'], api) ? (
{disabled || api.isRevision || (settings && settings.portalConfigurationOnlyModeEnabled) || isRestricted(['apim:api_create'], api) ? (
Copy link
Member

Choose a reason for hiding this comment

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

Do we need disabled check when api.isRevision is checked here?

fetchPolicies={fetchPolicies}
DraggablePolicyCard={DraggablePolicyCard}
isReadOnly={isReadOnly}
isReadOnly={disabled || isReadOnly}
Copy link
Member

Choose a reason for hiding this comment

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

Do we need disabled check when isReadOnly is checked?

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.

2 participants