Fix: unexpected navigation to Dynamic Endpoints in publisher portal #4761#1385
Fix: unexpected navigation to Dynamic Endpoints in publisher portal #4761#1385ShavinAnjithaAlpha wants to merge 4 commits into
Conversation
…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
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughEndpoint 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. ChangesEndpoint type handling
Estimated code review effort: 3 (Moderate) | ~25 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 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 winFix is correct and well-targeted.
Adding
INLINEto theprototypedbranch properly routes Mock Implementation throughcreateEndpointConfig('prototyped')and setsendpointImplementationType: 'INLINE', consistent with howEndpointOverview.jsxhandles INLINE via theset_inline_or_mocked_oasaction. 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,endpointImplementationTypeis already'INLINE'butswaggerwon't be updated, leaving the UI in an inconsistent state. The same pattern exists in theset_inline_or_mocked_oascase (lines 206-208). Consider extracting mock-script generation into auseEffectthat watchesendpointImplementationTypeas 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
📒 Files selected for processing (1)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx
| const config = createEndpointConfig(endpointType); | ||
| if (endpointType === 'prototyped') { | ||
| if (endpointType === 'prototyped' || endpointType === 'INLINE') { | ||
| const config = createEndpointConfig('prototyped'); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
📒 Files selected for processing (6)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsxportals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsxportals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/GenericEndpoint.jsxportals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsxportals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointConstants.jsportals/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
There was a problem hiding this comment.
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 winStale/duplicated JSDoc now misdescribes
updateSequenceBackends.The "Method to update the api.
@paramisRedirect ..." block at lines 277-281 previously documentedhandleSave. 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 newupdateSequenceBackends, 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 winUse a dedicated
ENDPOINT_TYPE_INLINEconstant here.endpointTypeis compared againstENDPOINT_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
📒 Files selected for processing (1)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx
| 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', | ||
| }), | ||
| ); | ||
| }); | ||
| } |
There was a problem hiding this comment.
🗄️ 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.
…nd handleSaveAndDeploy
73b99c3 to
31ff0fa
Compare
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.
|



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.jsxsendsendpointType: 'INLINE'for the Mock Implementation card, but theendpointImplementationTypereducer inEndpoints.jsxonly handled'prototyped', so it silently fell back to the Dynamic endpoint template and never setendpointImplementationType: '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.