Skip to content

Fix: unexpected navigation to Dynamic Endpoints in publisher portal #4761#1385

Open
ShavinAnjithaAlpha wants to merge 4 commits into
wso2:mainfrom
ShavinAnjithaAlpha:fix/4761-publisher-mock-ui-fix
Open

Fix: unexpected navigation to Dynamic Endpoints in publisher portal #4761#1385
ShavinAnjithaAlpha wants to merge 4 commits into
wso2:mainfrom
ShavinAnjithaAlpha:fix/4761-publisher-mock-ui-fix

Conversation

@ShavinAnjithaAlpha

Copy link
Copy Markdown
Contributor

Purpose

Fixes the Publisher UI bug where clicking Add on the Mock Implementation endpoint card opened the Dynamic Endpoint panel instead.

Fixes #4761

Issue Link

Approach

NewEndpointCreate.jsx sends endpointType: 'INLINE' for the Mock Implementation card, but the endpointImplementationType reducer in Endpoints.jsx only handled 'prototyped', so it silently fell back to the Dynamic endpoint template and never set endpointImplementationType: 'INLINE'. Updated the reducer to also handle 'INLINE', building the correct mock config and setting the flag the UI relies on to render the Mock Implementation panel.

…tedly

Fixes an issue in the API Publisher UI where configuring or adding a mock
implementation incorrectly triggers and displays the Dynamic Endpoints screen.

Resolves: #4761
@CLAassistant

CLAassistant commented Jul 8, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ff4dd671-1926-440b-b8e0-da89b5a3aef4

📥 Commits

Reviewing files that changed from the base of the PR and between 31ff0fa and 59930f2.

📒 Files selected for processing (1)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx

📝 Walkthrough

Walkthrough

Endpoint type and implementation values are centralized in shared constants. Reducer, configuration, endpoint creation, validation, save/deploy, selection, and rendering logic now use those constants, while inline and prototyped endpoint handling follows a unified configuration path.

Changes

Endpoint type handling

Layer / File(s) Summary
Endpoint constants and configuration
portals/publisher/.../Endpoints/endpointConstants.js, portals/publisher/.../Endpoints/endpointUtils.js
Adds shared endpoint type and implementation constants and uses them when creating prototyped endpoint configurations.
Reducer and save workflow
portals/publisher/.../Endpoints/Endpoints.jsx
Unifies prototyped and inline reducer handling and centralizes sequence-backend updates plus Swagger-versus-API persistence for save and deploy flows.
Endpoint creation, overview, and rendering
portals/publisher/.../Endpoints/NewEndpointCreate.jsx, portals/publisher/.../Endpoints/EndpointOverview.jsx, portals/publisher/.../Endpoints/GenericEndpoint.jsx
Uses shared constants for endpoint creation, selection, dispatch, validation, supported endpoint types, and conditional rendering.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: ashera96, heshansudarshana, hisanhunais, krishanx92, lasanthas

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the bug fix around Mock Implementation incorrectly opening the Dynamic Endpoints panel.
Description check ✅ Passed The description matches the PR purpose and accurately describes the reducer and Mock Implementation behavior change.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx (1)

173-186: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Fix is correct and well-targeted.

Adding INLINE to the prototyped branch properly routes Mock Implementation through createEndpointConfig('prototyped') and sets endpointImplementationType: 'INLINE', consistent with how EndpointOverview.jsx handles INLINE via the set_inline_or_mocked_oas action. The fallback for INLINE + non-mock returning 'ENDPOINT' is a reasonable default.

One pre-existing observation (not introduced by this PR): api.generateMockScripts(api.id) is invoked as a side effect inside the reducer at line 178. Reducers should ideally be pure, and this fire-and-forget promise has no error handling — if it rejects, endpointImplementationType is already 'INLINE' but swagger won't be updated, leaving the UI in an inconsistent state. The same pattern exists in the set_inline_or_mocked_oas case (lines 206-208). Consider extracting mock-script generation into a useEffect that watches endpointImplementationType as a follow-up improvement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx`
around lines 173 - 186, The `endpointImplementationType` branch in
`Endpoints.jsx` is triggering `api.generateMockScripts(api.id)` as a side effect
inside the reducer, which should be avoided and can leave
`endpointImplementationType` set to `INLINE` without updating `swagger` if the
promise fails. Move the mock-script generation out of this reducer logic into a
`useEffect` (or similar async handler) that reacts to the relevant state change,
and add rejection handling so failures are surfaced and the UI stays consistent.
Keep the existing `createEndpointConfig(...)` and `setSwagger(...)` flow, but
ensure the reducer remains pure and only returns state in the
`endpointImplementationType` case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx`:
- Around line 173-186: The `endpointImplementationType` branch in
`Endpoints.jsx` is triggering `api.generateMockScripts(api.id)` as a side effect
inside the reducer, which should be avoided and can leave
`endpointImplementationType` set to `INLINE` without updating `swagger` if the
promise fails. Move the mock-script generation out of this reducer logic into a
`useEffect` (or similar async handler) that reacts to the relevant state change,
and add rejection handling so failures are surfaced and the UI stays consistent.
Keep the existing `createEndpointConfig(...)` and `setSwagger(...)` flow, but
ensure the reducer remains pure and only returns state in the
`endpointImplementationType` case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0e7628a2-256b-4934-8917-7cd8c4683693

📥 Commits

Reviewing files that changed from the base of the PR and between 8721231 and de8229c.

📒 Files selected for processing (1)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 8, 2026
const config = createEndpointConfig(endpointType);
if (endpointType === 'prototyped') {
if (endpointType === 'prototyped' || endpointType === 'INLINE') {
const config = createEndpointConfig('prototyped');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

shall we use inline constants for these stringly-typed constants?

Replace duplicated 'prototyped'/'INLINE'/'ENDPOINT'/'MOCKED_OAS'/'mock'
string literals across Endpoints.jsx, EndpointOverview.jsx,
endpointUtils.js, NewEndpointCreate.jsx, and GenericEndpoint.jsx with
named constants in a new endpointConstants.js, per PR review feedback.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx`:
- Line 370: In the endpoint type condition within EndpointOverview, replace the
tautological OR between the two !== comparisons with an AND. Ensure the block
executes only when epType.key is neither ENDPOINT_IMPLEMENTATION_TYPE_INLINE nor
ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS.
🪄 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: 90e65090-f7b7-4856-b37a-d3723f7b83bb

📥 Commits

Reviewing files that changed from the base of the PR and between de8229c and adde311.

📒 Files selected for processing (6)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/GenericEndpoint.jsx
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsx
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointConstants.js
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointUtils.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx (1)

277-284: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Stale/duplicated JSDoc now misdescribes updateSequenceBackends.

The "Method to update the api. @param isRedirect ..." block at lines 277-281 previously documented handleSave. That function moved down and now has its own (correct) copy of this docstring at lines 385-389, but this original copy was left in place directly above the new updateSequenceBackends, which it doesn't describe.

Remove the stale docstring
-    /**
-     * Method to update the api.
-     *
-     * `@param` {boolean} isRedirect Used for dynamic endpoints to redirect to the runtime config page.
-     */
     /**
      * Delete/ upload the production and sandbox sequence backends based on the current backend lists.
      */
     const updateSequenceBackends = () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx`
around lines 277 - 284, Remove the stale “Method to update the api” JSDoc block
above updateSequenceBackends, including its obsolete isRedirect parameter
description; retain the correct documentation for handleSave at its current
location.
🧹 Nitpick comments (1)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx (1)

180-202: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a dedicated ENDPOINT_TYPE_INLINE constant here. endpointType is compared against ENDPOINT_IMPLEMENTATION_TYPE_INLINE, so this branch depends on two domains sharing the same 'INLINE' literal. A separate endpoint-type constant avoids that coupling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx`
around lines 180 - 202, Update the endpointType comparison in the
endpointImplementationType handler to use the dedicated ENDPOINT_TYPE_INLINE
constant instead of ENDPOINT_IMPLEMENTATION_TYPE_INLINE, while preserving the
existing prototyped and inline branch behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx`:
- Around line 353-368: Update persistEndpointConfig in the INLINE/MOCKED_OAS
branch to return the updateAPI(updatePayload) promise from the second then
callback, ensuring onComplete runs only after the endpoint update settles. Add
error handling for api.updateSwagger(swagger) failures using the existing alert
behavior, while preserving the current updateAPI error handling and completion
callback flow.
- Around line 285-341: Update updateSequenceBackends so each production and
sandbox backend chooses either deletion or upload instead of triggering both
requests concurrently when content is present. Chain the upload after the
corresponding delete completes, or structure the conditions as mutually
exclusive while preserving the existing success and error alerts.

---

Outside diff comments:
In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx`:
- Around line 277-284: Remove the stale “Method to update the api” JSDoc block
above updateSequenceBackends, including its obsolete isRedirect parameter
description; retain the correct documentation for handleSave at its current
location.

---

Nitpick comments:
In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx`:
- Around line 180-202: Update the endpointType comparison in the
endpointImplementationType handler to use the dedicated ENDPOINT_TYPE_INLINE
constant instead of ENDPOINT_IMPLEMENTATION_TYPE_INLINE, while preserving the
existing prototyped and inline branch behavior.
🪄 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: e1fc1747-92e1-42c8-9531-297f8e396d2b

📥 Commits

Reviewing files that changed from the base of the PR and between adde311 and 73b99c3.

📒 Files selected for processing (1)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx

Comment on lines +285 to 341
const updateSequenceBackends = () => {
if (productionBackendList?.length === 0 || (productionBackendList?.length > 0
&& productionBackendList[0].content)) {
api.deleteSequenceBackend(API_SECURITY_KEY_TYPE_PRODUCTION, api.id).then(() => {
Alert.success('Production Sequence backend deleted successfully');
})
.catch(() => {
Alert.error(intl.formatMessage({
id: 'Apis.Details.Endpoints.Endpoints.delete.sequence.backend.error',
defaultMessage: 'Error Deleting Production Sequence Backend',
}));
});
}

const { endpointConfig, endpointImplementationType, serviceInfo } = apiObject;
if (endpointConfig.endpoint_type === 'service') {
endpointConfig.endpoint_type = 'http';
if (sandBoxBackendList?.length === 0 || (sandBoxBackendList?.length > 0 && sandBoxBackendList[0].content)) {
api.deleteSequenceBackend(API_SECURITY_KEY_TYPE_SANDBOX, api.id).then(() => {
Alert.success('Sandbox Sequence backend deleted successfully');
})
.catch(() => {
Alert.error(intl.formatMessage({
id: 'Apis.Details.Endpoints.Endpoints.delete.sequence.backend.error',
defaultMessage: 'Error Deleting Sandbox Sequence Backend',
}));
});
}
setUpdating(true);
if (endpointConfig.endpoint_type === 'sequence_backend') {
if (productionBackendList?.length === 0 || (productionBackendList?.length > 0
&& productionBackendList[0].content)) {
api.deleteSequenceBackend(API_SECURITY_KEY_TYPE_PRODUCTION, api.id).then(() => {
Alert.success('Production Sequence backend deleted successfully');
if (productionBackendList?.length > 0 && productionBackendList[0].content) {
const productionBackend = productionBackendList[0];
api.uploadCustomBackend(productionBackend.content, API_SECURITY_KEY_TYPE_PRODUCTION, api.id)
.then(() => {
Alert.success('Custom backend uploaded successfully');
})
.catch(() => {
Alert.error(intl.formatMessage({
id: 'Apis.Details.Endpoints.Endpoints.delete.sequence.backend.error',
defaultMessage: 'Error Deleting Production Sequence Backend',
}));
});
}

if (sandBoxBackendList?.length === 0 || (sandBoxBackendList?.length > 0 && sandBoxBackendList[0].content)) {
api.deleteSequenceBackend(API_SECURITY_KEY_TYPE_SANDBOX, api.id).then(() => {
Alert.success('Sandbox Sequence backend deleted successfully');
.catch((error) => {
const backendMessage = error?.response?.body?.description;
Alert.error(
backendMessage || intl.formatMessage({
id: 'Apis.Details.Endpoints.Endpoints.upload.sequence.backend.error',
defaultMessage: 'Error Uploading Production Sequence Backend',
}),
);
});
}
if (sandBoxBackendList?.length > 0 && sandBoxBackendList[0].content) {
const sandBackend = sandBoxBackendList[0];
api.uploadCustomBackend(sandBackend.content, API_SECURITY_KEY_TYPE_SANDBOX, api.id)
.then(() => {
Alert.success('Custom backend uploaded successfully');
})
.catch(() => {
Alert.error(intl.formatMessage({
id: 'Apis.Details.Endpoints.Endpoints.delete.sequence.backend.error',
defaultMessage: 'Error Deleting Sandbox Sequence Backend',
}));
});
}
if (productionBackendList?.length > 0 && productionBackendList[0].content) {
const productionBackend = productionBackendList[0];
api.uploadCustomBackend(productionBackend.content, API_SECURITY_KEY_TYPE_PRODUCTION, api.id)
.then(() => {
Alert.success('Custom backend uploaded successfully');
})
.catch((error) => {
const backendMessage = error?.response?.body?.description;
Alert.error(
backendMessage || intl.formatMessage({
id: 'Apis.Details.Endpoints.Endpoints.upload.sequence.backend.error',
defaultMessage: 'Error Uploading Production Sequence Backend',
}),
);
});
}
if (sandBoxBackendList?.length > 0 && sandBoxBackendList[0].content) {
const sandBackend = sandBoxBackendList[0];
api.uploadCustomBackend(sandBackend.content, API_SECURITY_KEY_TYPE_SANDBOX, api.id)
.then(() => {
Alert.success('Custom backend uploaded successfully');
})
.catch((error) => {
const backendMessage = error?.response?.body?.description;
Alert.error(
backendMessage || intl.formatMessage({
id: 'Apis.Details.Endpoints.Endpoints.upload.sequence.backend.error',
defaultMessage: 'Error Uploading Sandbox Sequence Backend',
}),
);
});
}
.catch((error) => {
const backendMessage = error?.response?.body?.description;
Alert.error(
backendMessage || intl.formatMessage({
id: 'Apis.Details.Endpoints.Endpoints.upload.sequence.backend.error',
defaultMessage: 'Error Uploading Sandbox Sequence Backend',
}),
);
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx'

echo '--- surrounding lines ---'
sed -n '240,380p' "$file"

echo
echo '--- references to updateSequenceBackends ---'
rg -n "updateSequenceBackends|deleteSequenceBackend|uploadCustomBackend|API_SECURITY_KEY_TYPE_PRODUCTION|API_SECURITY_KEY_TYPE_SANDBOX" "$file"

Repository: wso2/apim-apps

Length of output: 7242


🏁 Script executed:

#!/bin/bash
set -euo pipefail
file='portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx'
sed -n '380,435p' "$file"

Repository: wso2/apim-apps

Length of output: 2181


Sequence backend delete/upload needs ordering
When content is present, the delete and upload branches are both true for production and sandbox, so both requests fire at once for the same backend. Chain the upload after the delete settles, or make the flow explicitly choose one action.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx`
around lines 285 - 341, Update updateSequenceBackends so each production and
sandbox backend chooses either deletion or upload instead of triggering both
requests concurrently when content is present. Chain the upload after the
corresponding delete completes, or structure the conditions as mutually
exclusive while preserving the existing success and error alerts.

@ShavinAnjithaAlpha
ShavinAnjithaAlpha force-pushed the fix/4761-publisher-mock-ui-fix branch from 73b99c3 to 31ff0fa Compare July 16, 2026 10:14
Changes the logical OR (`||`) to an AND (`&&`) operator inside `EndpointOverview.jsx` so the conditional block correctly skips execution when the endpoint type is either INLINE or MOCKED_OAS.
@sonarqubecloud

Copy link
Copy Markdown

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.

3 participants