From 4f5dbd07be3d6a2b90a48eeb1aaeb3a6614f4df5 Mon Sep 17 00:00:00 2001 From: Shavin Chandrawansha Date: Wed, 8 Jul 2026 14:35:48 +0530 Subject: [PATCH 1/7] fix(publisher): prevent dynamic endpoints screen from opening unexpectedly 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 --- .../src/app/components/Apis/Details/Endpoints/Endpoints.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx index 73593382450..2dd59f7318a 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx @@ -172,8 +172,8 @@ function Endpoints(props) { } case 'endpointImplementationType': { // set implementation status const { endpointType, implementationType } = value; - const config = createEndpointConfig(endpointType); - if (endpointType === 'prototyped') { + if (endpointType === 'prototyped' || endpointType === 'INLINE') { + const config = createEndpointConfig('prototyped'); if (implementationType === 'mock') { api.generateMockScripts(api.id).then((res) => { // generates mock/sample payloads setSwagger(res.obj); @@ -182,6 +182,7 @@ function Endpoints(props) { } return { ...initState, endpointConfig: config, endpointImplementationType: 'ENDPOINT' }; } + const config = createEndpointConfig(endpointType); return { ...initState, endpointConfig: config }; } case 'endpointSecurity': { // set endpoint security From 19e3edddc6427f43b6fcffdb6de054a6f1882c27 Mon Sep 17 00:00:00 2001 From: Shavin Chandrawansha Date: Wed, 15 Jul 2026 12:27:43 +0530 Subject: [PATCH 2/7] refactor(publisher): extract endpoint implementation type 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. --- .../Details/Endpoints/EndpointOverview.jsx | 63 +++++++++++-------- .../Apis/Details/Endpoints/Endpoints.jsx | 40 ++++++++---- .../Details/Endpoints/GenericEndpoint.jsx | 3 +- .../Details/Endpoints/NewEndpointCreate.jsx | 8 ++- .../Details/Endpoints/endpointConstants.js | 29 +++++++++ .../Apis/Details/Endpoints/endpointUtils.js | 7 ++- 6 files changed, 107 insertions(+), 43 deletions(-) create mode 100644 portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointConstants.js diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx index c195f8be2df..896e423eb7a 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx @@ -54,6 +54,12 @@ import EndpointSecurity from './GeneralConfiguration/EndpointSecurity'; import Credentials from './AWSLambda/Credentials.jsx'; import ServiceEndpoint from './ServiceEndpoint'; import CustomBackend from './CustomBackend'; +import { + ENDPOINT_TYPE_PROTOTYPED, + ENDPOINT_IMPLEMENTATION_TYPE_INLINE, + ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT, + ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS, +} from './endpointConstants'; const PREFIX = 'EndpointOverview'; @@ -162,11 +168,11 @@ const endpointTypes = [ { key: 'http', value: 'HTTP/REST Endpoint' }, { key: 'default', value: 'Dynamic Endpoints' }, { key: 'address', value: 'HTTP/SOAP Endpoint' }, - { key: 'prototyped', value: 'Prototype Endpoint' }, - { key: 'INLINE', value: 'Mock Implementation' }, + { key: ENDPOINT_TYPE_PROTOTYPED, value: 'Prototype Endpoint' }, + { key: ENDPOINT_IMPLEMENTATION_TYPE_INLINE, value: 'Mock Implementation' }, { key: 'awslambda', value: 'AWS Lambda' }, { key: 'service', value: 'Service Endpoint' }, - { key: 'MOCKED_OAS', value: 'Mock Implementation' }, + { key: ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS, value: 'Mock Implementation' }, { key: 'sequence_backend', value: 'Sequence Backend' }, { key: 'ws', value: 'Websocket Endpoint' }, ]; @@ -237,12 +243,12 @@ function EndpointOverview(props) { * */ const getEndpointType = (apiObject) => { const type = apiObject.endpointConfig && apiObject.endpointConfig.endpoint_type; - if (apiObject.endpointImplementationType === 'INLINE') { + if (apiObject.endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_INLINE) { return endpointTypes[4]; - } else if (apiObject.endpointImplementationType === 'MOCKED_OAS') { + } else if (apiObject.endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) { return endpointTypes[7]; - } else if (apiObject.endpointImplementationType === 'ENDPOINT' - && apiObject.endpointConfig.implementation_status === 'prototyped' + } else if (apiObject.endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT + && apiObject.endpointConfig.implementation_status === ENDPOINT_TYPE_PROTOTYPED && api.lifeCycleStatus === 'PROTOTYPED') { return endpointTypes[3]; } else if (type === 'http') { @@ -322,7 +328,7 @@ function EndpointOverview(props) { { key: 'service', value: 'Service Endpoint' }, { key: 'address', value: 'HTTP/SOAP Endpoint' }, { key: 'default', value: 'Dynamic Endpoints' }, - { key: 'INLINE', value: 'Mock Implementation' }, + { key: ENDPOINT_IMPLEMENTATION_TYPE_INLINE, value: 'Mock Implementation' }, { key: 'awslambda', value: 'AWS Lambda' }, ]; } @@ -361,7 +367,7 @@ function EndpointOverview(props) { if (epType.key === 'service') { getServices(); } - if (epType.key !== 'INLINE' || epType.key !== 'MOCKED_OAS') { + if (epType.key !== ENDPOINT_IMPLEMENTATION_TYPE_INLINE || epType.key !== ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) { setEndpointCategory({ prod: !!endpointConfig.production_endpoints, sandbox: !!endpointConfig.sandbox_endpoints, @@ -563,8 +569,8 @@ function EndpointOverview(props) { setTypeChangeConfirmation({ openDialog: false, serviceInfo: false }); setIsCustomBackendSelected(false); const selectedKey = typeChangeConfirmation.type || value; - if (selectedKey === 'INLINE' || selectedKey === 'MOCKED_OAS') { - const tmpConfig = createEndpointConfig('prototyped'); + if (selectedKey === ENDPOINT_IMPLEMENTATION_TYPE_INLINE || selectedKey === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) { + const tmpConfig = createEndpointConfig(ENDPOINT_TYPE_PROTOTYPED); endpointsDispatcher({ action: 'set_inline_or_mocked_oas', value: { @@ -572,12 +578,12 @@ function EndpointOverview(props) { endpointImplementationType: selectedKey, }, }); - } else if (selectedKey === 'prototyped') { + } else if (selectedKey === ENDPOINT_TYPE_PROTOTYPED) { const tmpConfig = createEndpointConfig(selectedKey); endpointsDispatcher({ action: 'set_prototyped', value: { - endpointImplementationType: 'ENDPOINT', + endpointImplementationType: ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT, endpointConfig: tmpConfig, }, }); @@ -586,7 +592,7 @@ function EndpointOverview(props) { endpointsDispatcher({ action: 'select_endpoint_type', value: { - endpointImplementationType: 'ENDPOINT', + endpointImplementationType: ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT, endpointConfig: { ...generatedEndpointConfig }, }, }); @@ -596,7 +602,7 @@ function EndpointOverview(props) { endpointsDispatcher({ action: 'select_endpoint_type', value: { - endpointImplementationType: 'ENDPOINT', + endpointImplementationType: ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT, endpointConfig: { ...generatedEndpointConfig }, }, }); @@ -605,7 +611,7 @@ function EndpointOverview(props) { endpointsDispatcher({ action: 'select_endpoint_type', value: { - endpointImplementationType: 'ENDPOINT', + endpointImplementationType: ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT, endpointConfig: { ...generatedEndpointConfig }, }, }); @@ -782,7 +788,8 @@ function EndpointOverview(props) { aria-label='EndpointType' name='endpointType' className={classes.radioGroup} - value={endpointType.key === 'MOCKED_OAS' ? 'INLINE' : endpointType.key} + value={endpointType.key === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS + ? ENDPOINT_IMPLEMENTATION_TYPE_INLINE : endpointType.key} onChange={handleEndpointTypeSelect} > {supportedEnpointTypes.map((endpoint) => { @@ -804,7 +811,8 @@ function EndpointOverview(props) { - {(endpointType.key === 'INLINE' || endpointType.key === 'MOCKED_OAS') ? + {(endpointType.key === ENDPOINT_IMPLEMENTATION_TYPE_INLINE + || endpointType.key === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) ? iff(Object.keys(swaggerDef.paths).length !== 0, - {endpointType.key === 'prototyped' + {endpointType.key === ENDPOINT_TYPE_PROTOTYPED ? ( )} - {endpointType.key === 'prototyped' ?
+ {endpointType.key === ENDPOINT_TYPE_PROTOTYPED ?
: (
{componentValidator.includes("typeSANDBOX") && @@ -1296,8 +1305,10 @@ function EndpointOverview(props) { )} - {endpointType.key === 'INLINE' || endpointType.key === 'MOCKED_OAS' || - endpointType.key === 'prototyped' || endpointType.key === 'awslambda' || api.type === 'WS' || endpointType.key === 'sequence_backend' + {endpointType.key === ENDPOINT_IMPLEMENTATION_TYPE_INLINE + || endpointType.key === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS + || endpointType.key === ENDPOINT_TYPE_PROTOTYPED || endpointType.key === 'awslambda' + || api.type === 'WS' || endpointType.key === 'sequence_backend' ?
: ( @@ -1315,10 +1326,10 @@ function EndpointOverview(props) { )} { - endpointType.key === 'INLINE' - || endpointType.key === 'MOCKED_OAS' + endpointType.key === ENDPOINT_IMPLEMENTATION_TYPE_INLINE + || endpointType.key === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS || endpointType.key === 'default' - || endpointType.key === 'prototyped' + || endpointType.key === ENDPOINT_TYPE_PROTOTYPED || endpointType.key === 'sequence_backend' || api.type === 'WS' || endpointType.key === 'awslambda' diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx index 2dd59f7318a..57190985f67 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx @@ -37,8 +37,15 @@ import MCPServerEndpoints from 'AppComponents/MCPServers/Details/Endpoints/Endpo import EndpointOverview from './EndpointOverview'; import AIEndpoints from './AIEndpoints/AIEndpoints'; import { createEndpointConfig, getEndpointTemplateByType } from './endpointUtils'; -import { API_SECURITY_KEY_TYPE_PRODUCTION, +import { API_SECURITY_KEY_TYPE_PRODUCTION, API_SECURITY_KEY_TYPE_SANDBOX } from '../Configuration/components/APISecurity/components/apiSecurityConstants'; +import { + ENDPOINT_TYPE_PROTOTYPED, + ENDPOINT_IMPLEMENTATION_TYPE_INLINE, + ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT, + ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS, + ENDPOINT_IMPLEMENTATION_METHOD_MOCK, +} from './endpointConstants'; const PREFIX = 'Endpoints'; @@ -172,15 +179,23 @@ function Endpoints(props) { } case 'endpointImplementationType': { // set implementation status const { endpointType, implementationType } = value; - if (endpointType === 'prototyped' || endpointType === 'INLINE') { - const config = createEndpointConfig('prototyped'); - if (implementationType === 'mock') { + if (endpointType === ENDPOINT_TYPE_PROTOTYPED || endpointType === ENDPOINT_IMPLEMENTATION_TYPE_INLINE) { + const config = createEndpointConfig(ENDPOINT_TYPE_PROTOTYPED); + if (implementationType === ENDPOINT_IMPLEMENTATION_METHOD_MOCK) { api.generateMockScripts(api.id).then((res) => { // generates mock/sample payloads setSwagger(res.obj); }); - return { ...initState, endpointConfig: config, endpointImplementationType: 'INLINE' }; + return { + ...initState, + endpointConfig: config, + endpointImplementationType: ENDPOINT_IMPLEMENTATION_TYPE_INLINE, + }; } - return { ...initState, endpointConfig: config, endpointImplementationType: 'ENDPOINT' }; + return { + ...initState, + endpointConfig: config, + endpointImplementationType: ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT, + }; } const config = createEndpointConfig(endpointType); return { ...initState, endpointConfig: config }; @@ -202,7 +217,7 @@ function Endpoints(props) { } case 'set_inline_or_mocked_oas': { const { endpointImplementationType, endpointConfig } = value; - if (endpointImplementationType === 'INLINE') { + if (endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_INLINE) { api.generateMockScripts(api.id).then((res) => { // generates mock/sample payloads setSwagger(res.obj); }); @@ -329,7 +344,8 @@ function Endpoints(props) { }); } } - if (endpointImplementationType === 'INLINE' || endpointImplementationType === 'MOCKED_OAS') { + if (endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_INLINE + || endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) { api.updateSwagger(swagger).then((resp) => { setSwagger(resp.obj); }).then(() => { @@ -436,7 +452,8 @@ function Endpoints(props) { }); } } - if (endpointImplementationType === 'INLINE' || endpointImplementationType === 'MOCKED_OAS') { + if (endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_INLINE + || endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) { api.updateSwagger(swagger).then((resp) => { setSwagger(resp.obj); }).then(() => { @@ -678,8 +695,9 @@ function Endpoints(props) { } } else { let isValidEndpoint = false; - if (endpointConfig.implementation_status === 'prototyped' && api.lifeCycleStatus === 'PROTOTYPED') { - if (implementationType === 'ENDPOINT') { + if (endpointConfig.implementation_status === ENDPOINT_TYPE_PROTOTYPED + && api.lifeCycleStatus === 'PROTOTYPED') { + if (implementationType === ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT) { if (endpointConfig.production_endpoints && endpointConfig.production_endpoints.url === '') { return { isValid: false, diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/GenericEndpoint.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/GenericEndpoint.jsx index 367620acf54..155058728e9 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/GenericEndpoint.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/GenericEndpoint.jsx @@ -32,6 +32,7 @@ import { isRestricted } from 'AppData/AuthManager'; import APIContext from 'AppComponents/Apis/Details/components/ApiContext'; import API from 'AppData/api'; import { green } from '@mui/material/colors'; +import { ENDPOINT_TYPE_PROTOTYPED } from './endpointConstants'; const PREFIX = 'GenericEndpoint'; @@ -224,7 +225,7 @@ function GenericEndpoint(props) { )} )} - {type === 'prototyped' + {type === ENDPOINT_TYPE_PROTOTYPED ?
: ( <> diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsx index 602bfe43eb9..59c07277e8d 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsx @@ -33,6 +33,10 @@ import { CardActions, } from '@mui/material'; import PropTypes from 'prop-types'; +import { + ENDPOINT_IMPLEMENTATION_TYPE_INLINE, + ENDPOINT_IMPLEMENTATION_METHOD_MOCK, +} from './endpointConstants'; const PREFIX = 'NewEndpointCreate'; @@ -97,7 +101,7 @@ function NewEndpointCreate(props) { componentValidator, } = props; const intl = useIntl(); - const [endpointImplType, setImplType] = useState('mock'); + const [endpointImplType, setImplType] = useState(ENDPOINT_IMPLEMENTATION_METHOD_MOCK); const endpointTypes = [ { type: 'http', @@ -152,7 +156,7 @@ function NewEndpointCreate(props) { disabled: ['SOAPTOREST', 'GRAPHQL', 'SSE', 'SOAP', 'HTTP'], }, { - type: 'INLINE', + type: ENDPOINT_IMPLEMENTATION_TYPE_INLINE, name: intl.formatMessage({ id: 'Apis.Details.Endpoints.NewEndpointCreate.create.prototype.endpoint', defaultMessage: 'Mock Implementation', diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointConstants.js b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointConstants.js new file mode 100644 index 00000000000..a176f0bd129 --- /dev/null +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointConstants.js @@ -0,0 +1,29 @@ +/** + * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const ENDPOINT_TYPE_PROTOTYPED = 'prototyped'; +const ENDPOINT_IMPLEMENTATION_TYPE_INLINE = 'INLINE'; +const ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT = 'ENDPOINT'; +const ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS = 'MOCKED_OAS'; +const ENDPOINT_IMPLEMENTATION_METHOD_MOCK = 'mock'; + +export { + ENDPOINT_TYPE_PROTOTYPED, + ENDPOINT_IMPLEMENTATION_TYPE_INLINE, + ENDPOINT_IMPLEMENTATION_TYPE_ENDPOINT, + ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS, + ENDPOINT_IMPLEMENTATION_METHOD_MOCK, +}; \ No newline at end of file diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointUtils.js b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointUtils.js index 34c86b7b001..456b6c7bd16 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointUtils.js +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/endpointUtils.js @@ -15,6 +15,7 @@ */ import cloneDeep from 'lodash.clonedeep'; +import { ENDPOINT_TYPE_PROTOTYPED } from './endpointConstants'; /** * Utility method to get the endpoint property name based on the given endpoint type and category. @@ -140,7 +141,7 @@ function getEndpointConfigByImpl(implementationType) { const tmpEndpointConfig = {}; if (implementationType === 'PROTOTYPED') { tmpEndpointConfig.endpoint_type = 'http'; - tmpEndpointConfig.implementation_status = 'prototyped'; + tmpEndpointConfig.implementation_status = ENDPOINT_TYPE_PROTOTYPED; tmpEndpointConfig.production_endpoints = { config: null, url: 'http://localhost' }; tmpEndpointConfig.sandbox_endpoints = { config: null, url: 'http://localhost' }; } else { @@ -184,8 +185,8 @@ function createEndpointConfig(endpointType) { tmpEndpointConfig.endpoint_type = 'ws'; tmpEndpointConfig.failOver = false; break; - case 'prototyped': - tmpEndpointConfig.implementation_status = 'prototyped'; + case ENDPOINT_TYPE_PROTOTYPED: + tmpEndpointConfig.implementation_status = ENDPOINT_TYPE_PROTOTYPED; tmpEndpointConfig.endpoint_type = 'http'; tmpEndpointConfig.production_endpoints = { config: null, url: 'http://localhost' }; tmpEndpointConfig.sandbox_endpoints = { config: null, url: 'http://localhost' }; From 2303f4a114cd1b86ba8227e0bbcb6c8a3154bbe0 Mon Sep 17 00:00:00 2001 From: Shavin Chandrawansha Date: Thu, 16 Jul 2026 11:25:16 +0530 Subject: [PATCH 3/7] refactor(publisher): dedupe endpoint save logic between handleSave and handleSaveAndDeploy --- .../Apis/Details/Endpoints/Endpoints.jsx | 291 +++++++----------- 1 file changed, 117 insertions(+), 174 deletions(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx index 57190985f67..d5e543e1c4b 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx @@ -279,90 +279,98 @@ function Endpoints(props) { * * @param {boolean} isRedirect Used for dynamic endpoints to redirect to the runtime config page. */ - const handleSave = (isRedirect) => { + /** + * Delete/ upload the production and sandbox sequence backends based on the current backend lists. + */ + 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', + }), + ); + }); } + }; + + /** + * Update the swagger (for INLINE/ MOCKED_OAS implementations) or the API object, then invoke the completion + * callback. Shared by handleSave and handleSaveAndDeploy, which only differ in the update payload and what + * happens once the update settles. + * + * @param {string} endpointImplementationType The api implementation type (INLINE/ ENDPOINT/ MOCKED_OAS). + * @param {object} updatePayload The payload to send via updateAPI for INLINE/ MOCKED_OAS implementations. + * @param {Function} onComplete Callback invoked once the update settles. + */ + const persistEndpointConfig = (endpointImplementationType, updatePayload, onComplete) => { if (endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_INLINE || endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) { api.updateSwagger(swagger).then((resp) => { setSwagger(resp.obj); - }).then(() => { - updateAPI({ endpointConfig, endpointImplementationType, serviceInfo }) - .catch((error) => { - if (error.response) { - Alert.error(error.response.body.description); - } else { - Alert.error('Error occurred while updating endpoint configurations'); - } - }); - }).finally(() => { - setUpdating(false); - if (isRedirect) { - history.push('/apis/' + api.id + '/policies'); - } - }); + }).then(() => updateAPI(updatePayload) + .catch((error) => { + if (error.response) { + Alert.error(error.response.body.description); + } else { + Alert.error('Error occurred while updating endpoint configurations'); + } + })) + .catch((error) => { + if (error.response) { + Alert.error(error.response.body.description); + } else { + Alert.error('Error occurred while updating endpoint configurations'); + } + }) + .finally(onComplete); } else { const apiObjectCopy = cloneDeep(apiObject); if (apiObjectCopy.endpointConfig.endpoint_type === 'service') { @@ -376,15 +384,36 @@ function Endpoints(props) { Alert.error('Error occurred while updating endpoint configurations'); } }) - .finally(() => { - setUpdating(false); - if (isRedirect) { - history.push('/apis/' + api.id + '/policies'); - } - }); + .finally(onComplete); } }; + /** + * Method to update the api. + * + * @param {boolean} isRedirect Used for dynamic endpoints to redirect to the runtime config page. + */ + const handleSave = (isRedirect) => { + const { endpointConfig, endpointImplementationType, serviceInfo } = apiObject; + if (endpointConfig.endpoint_type === 'service') { + endpointConfig.endpoint_type = 'http'; + } + setUpdating(true); + if (endpointConfig.endpoint_type === 'sequence_backend') { + updateSequenceBackends(); + } + persistEndpointConfig( + endpointImplementationType, + { endpointConfig, endpointImplementationType, serviceInfo }, + () => { + setUpdating(false); + if (isRedirect) { + history.push('/apis/' + api.id + '/policies'); + } + }, + ); + }; + const handleSaveAndDeploy = () => { const { endpointConfig, endpointImplementationType, endpointSecurity, serviceInfo } = apiObject; if (endpointConfig.endpoint_type === 'service') { @@ -392,103 +421,17 @@ function Endpoints(props) { } 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'); - }) - .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(() => { - 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', - }), - ); - }); - } + updateSequenceBackends(); } - if (endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_INLINE - || endpointImplementationType === ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) { - api.updateSwagger(swagger).then((resp) => { - setSwagger(resp.obj); - }).then(() => { - updateAPI({ endpointConfig, endpointImplementationType, endpointSecurity, serviceInfo }) - .catch((error) => { - if (error.response) { - Alert.error(error.response.body.description); - } else { - Alert.error('Error occurred while updating endpoint configurations'); - } - }); - }).finally(() => history.push({ + persistEndpointConfig( + endpointImplementationType, + { endpointConfig, endpointImplementationType, endpointSecurity, serviceInfo }, + () => history.push({ pathname: api.isAPIProduct() ? `/api-products/${api.id}/deployments` : `/apis/${api.id}/deployments`, state: 'deploy', - })); - } else { - const apiObjectCopy = cloneDeep(apiObject); - if (apiObjectCopy.endpointConfig.endpoint_type === 'service') { - apiObjectCopy.endpointConfig.endpoint_type = 'http'; - } - updateAPI(apiObjectCopy) - .catch((error) => { - if (error.response) { - Alert.error(error.response.body.description); - } else { - Alert.error('Error occurred while updating endpoint configurations'); - } - }) - .finally(() => history.push({ - pathname: api.isAPIProduct() ? `/api-products/${api.id}/deployments` - : `/apis/${api.id}/deployments`, - state: 'deploy', - })); - } + }), + ); }; /** From 57d4666fa55bc5ba8f1db9b3ae63d92ca8ce40e9 Mon Sep 17 00:00:00 2001 From: Shavin Chandrawansha Date: Fri, 17 Jul 2026 10:46:52 +0530 Subject: [PATCH 4/7] Fix tautological endpoint type condition in publisher portal 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. --- .../app/components/Apis/Details/Endpoints/EndpointOverview.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx index 896e423eb7a..ab740432867 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx @@ -367,7 +367,7 @@ function EndpointOverview(props) { if (epType.key === 'service') { getServices(); } - if (epType.key !== ENDPOINT_IMPLEMENTATION_TYPE_INLINE || epType.key !== ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) { + if (epType.key !== ENDPOINT_IMPLEMENTATION_TYPE_INLINE && epType.key !== ENDPOINT_IMPLEMENTATION_TYPE_MOCKED_OAS) { setEndpointCategory({ prod: !!endpointConfig.production_endpoints, sandbox: !!endpointConfig.sandbox_endpoints, From b403028103fd00bce76dd95e5872a7079556b15f Mon Sep 17 00:00:00 2001 From: Shavin Chandrawansha Date: Mon, 20 Jul 2026 11:06:56 +0530 Subject: [PATCH 5/7] fix(publisher): chain sequence backend delete and upload requests to avoid race condition --- .../Apis/Details/Endpoints/Endpoints.jsx | 177 ++++++++++-------- 1 file changed, 96 insertions(+), 81 deletions(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx index d5e543e1c4b..921eab39110 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx @@ -282,65 +282,76 @@ function Endpoints(props) { /** * Delete/ upload the production and sandbox sequence backends based on the current backend lists. */ - 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 deleteSequenceBackendOf = (keyType, deleteErrorMessage) => api + .deleteSequenceBackend(keyType, api.id) + .then(() => { + Alert.success(keyType === API_SECURITY_KEY_TYPE_PRODUCTION + ? 'Production Sequence backend deleted successfully' + : 'Sandbox Sequence backend deleted successfully'); + }) + .catch(() => { + Alert.error(deleteErrorMessage); + }); + + const uploadSequenceBackendOf = (keyType, content, uploadErrorMessage) => api + .uploadCustomBackend(content, keyType, api.id) + .then(() => { + Alert.success('Custom backend uploaded successfully'); + }) + .catch((error) => { + const backendMessage = error?.response?.body?.description; + Alert.error(backendMessage || uploadErrorMessage); + }); - 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', - })); - }); - } - 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', - }), - ); - }); - } + /** + * Delete a sequence backend of the given type, then, only once that delete has settled, upload its + * replacement content if any was provided. Chaining the upload off the delete's promise (rather than + * firing both at once) keeps the two requests deterministic instead of racing against each other. + */ + const updateSequenceBackendOf = (keyType, backendList, deleteErrorMessage, uploadErrorMessage) => { + const shouldDelete = backendList?.length === 0 + || (backendList?.length > 0 && backendList[0].content); + const shouldUpload = backendList?.length > 0 && backendList[0].content; + + const deletePromise = shouldDelete + ? deleteSequenceBackendOf(keyType, deleteErrorMessage) + : Promise.resolve(); + + return deletePromise.then(() => { + if (shouldUpload) { + return uploadSequenceBackendOf(keyType, backendList[0].content, uploadErrorMessage); + } + return Promise.resolve(); + }); }; + const updateSequenceBackends = () => Promise.all([ + updateSequenceBackendOf( + API_SECURITY_KEY_TYPE_PRODUCTION, + productionBackendList, + intl.formatMessage({ + id: 'Apis.Details.Endpoints.Endpoints.delete.sequence.backend.error', + defaultMessage: 'Error Deleting Production Sequence Backend', + }), + intl.formatMessage({ + id: 'Apis.Details.Endpoints.Endpoints.upload.sequence.backend.error', + defaultMessage: 'Error Uploading Production Sequence Backend', + }), + ), + updateSequenceBackendOf( + API_SECURITY_KEY_TYPE_SANDBOX, + sandBoxBackendList, + intl.formatMessage({ + id: 'Apis.Details.Endpoints.Endpoints.delete.sequence.backend.error', + defaultMessage: 'Error Deleting Sandbox Sequence Backend', + }), + intl.formatMessage({ + id: 'Apis.Details.Endpoints.Endpoints.upload.sequence.backend.error', + defaultMessage: 'Error Uploading Sandbox Sequence Backend', + }), + ), + ]); + /** * Update the swagger (for INLINE/ MOCKED_OAS implementations) or the API object, then invoke the completion * callback. Shared by handleSave and handleSaveAndDeploy, which only differ in the update payload and what @@ -399,19 +410,21 @@ function Endpoints(props) { endpointConfig.endpoint_type = 'http'; } setUpdating(true); - if (endpointConfig.endpoint_type === 'sequence_backend') { - updateSequenceBackends(); - } - persistEndpointConfig( - endpointImplementationType, - { endpointConfig, endpointImplementationType, serviceInfo }, - () => { - setUpdating(false); - if (isRedirect) { - history.push('/apis/' + api.id + '/policies'); - } - }, - ); + const sequenceBackendsUpdated = endpointConfig.endpoint_type === 'sequence_backend' + ? updateSequenceBackends() + : Promise.resolve(); + sequenceBackendsUpdated.then(() => { + persistEndpointConfig( + endpointImplementationType, + { endpointConfig, endpointImplementationType, serviceInfo }, + () => { + setUpdating(false); + if (isRedirect) { + history.push('/apis/' + api.id + '/policies'); + } + }, + ); + }); }; const handleSaveAndDeploy = () => { @@ -420,18 +433,20 @@ function Endpoints(props) { endpointConfig.endpoint_type = 'http'; } setUpdating(true); - if (endpointConfig.endpoint_type === 'sequence_backend') { - updateSequenceBackends(); - } - persistEndpointConfig( - endpointImplementationType, - { endpointConfig, endpointImplementationType, endpointSecurity, serviceInfo }, - () => history.push({ - pathname: api.isAPIProduct() ? `/api-products/${api.id}/deployments` - : `/apis/${api.id}/deployments`, - state: 'deploy', - }), - ); + const sequenceBackendsUpdated = endpointConfig.endpoint_type === 'sequence_backend' + ? updateSequenceBackends() + : Promise.resolve(); + sequenceBackendsUpdated.then(() => { + persistEndpointConfig( + endpointImplementationType, + { endpointConfig, endpointImplementationType, endpointSecurity, serviceInfo }, + () => history.push({ + pathname: api.isAPIProduct() ? `/api-products/${api.id}/deployments` + : `/apis/${api.id}/deployments`, + state: 'deploy', + }), + ); + }); }; /** From df0fd8ede7828505f25a8531630a0a54cc2208ad Mon Sep 17 00:00:00 2001 From: Shavin Chandrawansha Date: Thu, 30 Jul 2026 09:27:21 +0530 Subject: [PATCH 6/7] fix(publisher): avoid redundant Promise.resolve() in sequence backend update chain Refactor updateSequenceBackendOf to use async/await instead of manually chaining .then() with Promise.resolve() placeholders, resolving the SonarQube S7746 warning while preserving the delete-then-upload ordering. --- .../Apis/Details/Endpoints/Endpoints.jsx | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx index 921eab39110..bc96f1259a2 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/Endpoints.jsx @@ -308,21 +308,17 @@ function Endpoints(props) { * replacement content if any was provided. Chaining the upload off the delete's promise (rather than * firing both at once) keeps the two requests deterministic instead of racing against each other. */ - const updateSequenceBackendOf = (keyType, backendList, deleteErrorMessage, uploadErrorMessage) => { + const updateSequenceBackendOf = async (keyType, backendList, deleteErrorMessage, uploadErrorMessage) => { const shouldDelete = backendList?.length === 0 || (backendList?.length > 0 && backendList[0].content); const shouldUpload = backendList?.length > 0 && backendList[0].content; - const deletePromise = shouldDelete - ? deleteSequenceBackendOf(keyType, deleteErrorMessage) - : Promise.resolve(); - - return deletePromise.then(() => { - if (shouldUpload) { - return uploadSequenceBackendOf(keyType, backendList[0].content, uploadErrorMessage); - } - return Promise.resolve(); - }); + if (shouldDelete) { + await deleteSequenceBackendOf(keyType, deleteErrorMessage); + } + if (shouldUpload) { + await uploadSequenceBackendOf(keyType, backendList[0].content, uploadErrorMessage); + } }; const updateSequenceBackends = () => Promise.all([ From a0f909db1ca07c2883054eec18ffa8728b4e68ac Mon Sep 17 00:00:00 2001 From: Shavin Chandrawansha Date: Thu, 30 Jul 2026 09:28:53 +0530 Subject: [PATCH 7/7] Rename useState setter to match state variable naming convention Rename setImplType to setEndpointImplType to follow the [value, setValue] destructuring pattern expected by SonarQube, with no behavioral change. --- .../components/Apis/Details/Endpoints/NewEndpointCreate.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsx index 59c07277e8d..894bb9f6142 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/NewEndpointCreate.jsx @@ -101,7 +101,7 @@ function NewEndpointCreate(props) { componentValidator, } = props; const intl = useIntl(); - const [endpointImplType, setImplType] = useState(ENDPOINT_IMPLEMENTATION_METHOD_MOCK); + const [endpointImplType, setEndpointImplType] = useState(ENDPOINT_IMPLEMENTATION_METHOD_MOCK); const endpointTypes = [ { type: 'http', @@ -244,7 +244,9 @@ function NewEndpointCreate(props) { name='endpointType' className={classes.radioGroup} value={endpointImplType} - onChange={(event) => { setImplType(event.target.value); }} + onChange={(event) => { + setEndpointImplType(event.target.value); + }} > {type.options.filter((types) => !types.disabled .includes(apiType)).map(((option) => {