From d21723de73a204aec3375eac1c0c73b0aae5e5fc Mon Sep 17 00:00:00 2001 From: ruwinirathnamalala Date: Fri, 27 Mar 2026 15:02:00 +0530 Subject: [PATCH 1/4] Fix for bug #945 MCQ payload index bug --- .../MultiChoiceQuestionContent.tsx | 9 ++++++--- GUI/src/components/FlowElementsPopup/index.tsx | 15 ++++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/GUI/src/components/FlowElementsPopup/MultiChoiceQuestionContent.tsx b/GUI/src/components/FlowElementsPopup/MultiChoiceQuestionContent.tsx index 855731a01..25801e1d6 100644 --- a/GUI/src/components/FlowElementsPopup/MultiChoiceQuestionContent.tsx +++ b/GUI/src/components/FlowElementsPopup/MultiChoiceQuestionContent.tsx @@ -38,6 +38,11 @@ const MultiChoiceQuestionContent: FC = ({ const node = useServiceStore((state) => state.selectedNode); const serviceName = useServiceStore((state) => removeTrailingUnderscores(state.serviceNameDashed())); const selectedService = useServiceListStore((state) => state.selectedService); + const mcqNodeNumber = (() => { + const label = node?.data.label ?? ''; + const match = label.match(/(\d+)$/); + return match ? match[1] : '1'; + })(); const handleEdit = (idx: number) => { setEditIndex(idx); @@ -75,9 +80,7 @@ const MultiChoiceQuestionContent: FC = ({ { id: generateUniqueId(), title: '', - payload: `#service, /${selectedService?.type ?? 'POST'}/services/active/${serviceName}_mcq_${ - node?.data.label[node?.data.label.length - 1] - }_${buttons.length}`, + payload: `#service, /${selectedService?.type ?? 'POST'}/services/active/${serviceName}_mcq_${mcqNodeNumber}_${buttons.length}`, }, ]; setButtons(newButtons); diff --git a/GUI/src/components/FlowElementsPopup/index.tsx b/GUI/src/components/FlowElementsPopup/index.tsx index 39f1b3f33..c3a7f7abc 100644 --- a/GUI/src/components/FlowElementsPopup/index.tsx +++ b/GUI/src/components/FlowElementsPopup/index.tsx @@ -54,25 +54,26 @@ const FlowElementsPopup: React.FC = () => { const assignElements = useServiceStore((state) => state.assignElements); const endpointsVariables = useServiceStore((state) => state.endpointsResponseVariables); const stepType = node?.data.stepType; + const mcqNodeNumber = useMemo(() => { + const label = node?.data.label ?? ''; + const match = label.match(/(\d+)$/); + return match ? match[1] : '1'; + }, [node?.data.label]); const defaultMultiChoiceQuestionButtons = useMemo( () => [ { id: '1', title: 'Jah', - payload: `#service, /${selectedService?.type ?? 'POST'}/services/active/${serviceName}_mcq_${ - node?.data.label[node?.data.label.length - 1] - }_0`, + payload: `#service, /${selectedService?.type ?? 'POST'}/services/active/${serviceName}_mcq_${mcqNodeNumber}_0`, }, { id: '2', title: 'Ei', - payload: `#service, /${selectedService?.type ?? 'POST'}/services/active/${serviceName}_mcq_${ - node?.data.label[node?.data.label.length - 1] - }_1`, + payload: `#service, /${selectedService?.type ?? 'POST'}/services/active/${serviceName}_mcq_${mcqNodeNumber}_1`, }, ], - [selectedService?.type, serviceName, node?.data.label], + [selectedService?.type, serviceName, mcqNodeNumber], ); const defaultDynamicChoices: DynamicChoices = useMemo( From cf5bd2e28f12aa4b69eb0a9fddcdbeffffa5e19a Mon Sep 17 00:00:00 2001 From: ruwinirathnamalala Date: Fri, 27 Mar 2026 16:19:51 +0530 Subject: [PATCH 2/4] PR sonar issues fixed --- .../FlowElementsPopup/MultiChoiceQuestionContent.tsx | 11 ++++------- GUI/src/components/FlowElementsPopup/index.tsx | 12 ++++++------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/GUI/src/components/FlowElementsPopup/MultiChoiceQuestionContent.tsx b/GUI/src/components/FlowElementsPopup/MultiChoiceQuestionContent.tsx index 25801e1d6..3a2d42a44 100644 --- a/GUI/src/components/FlowElementsPopup/MultiChoiceQuestionContent.tsx +++ b/GUI/src/components/FlowElementsPopup/MultiChoiceQuestionContent.tsx @@ -5,7 +5,7 @@ import { MdCheck, MdDeleteOutline, MdEdit } from 'react-icons/md'; import useServiceStore from 'store/new-services.store'; import useServiceListStore from 'store/services.store'; import { generateUniqueId } from 'utils/flow-utils'; -import { removeTrailingUnderscores } from 'utils/string-util'; +import { getLastDigits, removeTrailingUnderscores } from 'utils/string-util'; import { v4 } from 'uuid'; import Button from '../Button'; @@ -15,7 +15,7 @@ import Track from '../Track'; import './styles.scss'; -const maxButtons = parseInt((import.meta.env.REACT_APP_MULTI_CHOICE_QUESTION_MAX_BUTTONS as string) ?? '4'); +const maxButtons = Number.parseInt((import.meta.env.REACT_APP_MULTI_CHOICE_QUESTION_MAX_BUTTONS as string) ?? '4'); export interface MultiChoiceQuestionContentProps { question: string; @@ -38,11 +38,8 @@ const MultiChoiceQuestionContent: FC = ({ const node = useServiceStore((state) => state.selectedNode); const serviceName = useServiceStore((state) => removeTrailingUnderscores(state.serviceNameDashed())); const selectedService = useServiceListStore((state) => state.selectedService); - const mcqNodeNumber = (() => { - const label = node?.data.label ?? ''; - const match = label.match(/(\d+)$/); - return match ? match[1] : '1'; - })(); + + const mcqNodeNumber = String(getLastDigits(node?.data.label ?? '')); const handleEdit = (idx: number) => { setEditIndex(idx); diff --git a/GUI/src/components/FlowElementsPopup/index.tsx b/GUI/src/components/FlowElementsPopup/index.tsx index c3a7f7abc..c2be85079 100644 --- a/GUI/src/components/FlowElementsPopup/index.tsx +++ b/GUI/src/components/FlowElementsPopup/index.tsx @@ -12,7 +12,7 @@ import { EndpointData } from 'types/endpoint'; import { MultiChoiceQuestionButton } from 'types/multi-choice-question'; import { NodeDataProps } from 'types/service-flow'; import { getValueByPath } from 'utils/object-util'; -import { isTemplate, removeTrailingUnderscores, stringToTemplate, templateToString } from 'utils/string-util'; +import { getLastDigits, isTemplate, removeTrailingUnderscores, stringToTemplate, templateToString } from 'utils/string-util'; import { Button, Track } from '..'; import Popup from '../Popup'; @@ -54,11 +54,11 @@ const FlowElementsPopup: React.FC = () => { const assignElements = useServiceStore((state) => state.assignElements); const endpointsVariables = useServiceStore((state) => state.endpointsResponseVariables); const stepType = node?.data.stepType; - const mcqNodeNumber = useMemo(() => { - const label = node?.data.label ?? ''; - const match = label.match(/(\d+)$/); - return match ? match[1] : '1'; - }, [node?.data.label]); + + const mcqNodeNumber = useMemo( + () => String(getLastDigits(node?.data.label ?? '')), + [node?.data.label], + ); const defaultMultiChoiceQuestionButtons = useMemo( () => [ From 22e06e94f7688f7148d642b810e46623f221610d Mon Sep 17 00:00:00 2001 From: ruwinirathnamalala Date: Mon, 30 Mar 2026 17:49:58 +0530 Subject: [PATCH 3/4] PR sonar issues fixed --- GUI/src/components/FlowElementsPopup/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GUI/src/components/FlowElementsPopup/index.tsx b/GUI/src/components/FlowElementsPopup/index.tsx index c2be85079..07fcc289b 100644 --- a/GUI/src/components/FlowElementsPopup/index.tsx +++ b/GUI/src/components/FlowElementsPopup/index.tsx @@ -226,7 +226,7 @@ const FlowElementsPopup: React.FC = () => { }; const prepareAssignForSaving = (updatedNode: Node) => { - const flatEndpointVariables = endpointsVariables.map((endpoint) => endpoint.chips).flat(); + const flatEndpointVariables = endpointsVariables.flatMap((endpoint) => endpoint.chips); assignElements.forEach((element) => { const key = removeTrailingUnderscores(element.key); element.key = key; From 31900a47d6d1b95897c93f8481e47e0da6b35bf6 Mon Sep 17 00:00:00 2001 From: ruwinirathnamalala Date: Tue, 31 Mar 2026 17:39:17 +0530 Subject: [PATCH 4/4] formatting issues fixed --- .../components/FlowElementsPopup/index.tsx | 19 +++++++++---------- GUI/src/components/Markdowify/index.tsx | 4 ++-- GUI/src/services/service-builder.ts | 10 ++-------- GUI/src/store/new-services.store.ts | 2 +- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/GUI/src/components/FlowElementsPopup/index.tsx b/GUI/src/components/FlowElementsPopup/index.tsx index 07fcc289b..f4105d71b 100644 --- a/GUI/src/components/FlowElementsPopup/index.tsx +++ b/GUI/src/components/FlowElementsPopup/index.tsx @@ -12,7 +12,13 @@ import { EndpointData } from 'types/endpoint'; import { MultiChoiceQuestionButton } from 'types/multi-choice-question'; import { NodeDataProps } from 'types/service-flow'; import { getValueByPath } from 'utils/object-util'; -import { getLastDigits, isTemplate, removeTrailingUnderscores, stringToTemplate, templateToString } from 'utils/string-util'; +import { + getLastDigits, + isTemplate, + removeTrailingUnderscores, + stringToTemplate, + templateToString, +} from 'utils/string-util'; import { Button, Track } from '..'; import Popup from '../Popup'; @@ -55,10 +61,7 @@ const FlowElementsPopup: React.FC = () => { const endpointsVariables = useServiceStore((state) => state.endpointsResponseVariables); const stepType = node?.data.stepType; - const mcqNodeNumber = useMemo( - () => String(getLastDigits(node?.data.label ?? '')), - [node?.data.label], - ); + const mcqNodeNumber = useMemo(() => String(getLastDigits(node?.data.label ?? '')), [node?.data.label]); const defaultMultiChoiceQuestionButtons = useMemo( () => [ @@ -373,11 +376,7 @@ const FlowElementsPopup: React.FC = () => { })); const updatedEdges = edges.map((edge) => { - if ( - !edge.label || - edge.source !== originalNode.id || - !connectedEdges.some((ce) => ce.id === edge.id) - ) + if (!edge.label || edge.source !== originalNode.id || !connectedEdges.some((ce) => ce.id === edge.id)) return edge; const rename = renamedButtons.find((r) => r.oldTitle === edge.label); if (rename) { diff --git a/GUI/src/components/Markdowify/index.tsx b/GUI/src/components/Markdowify/index.tsx index 55b72aba8..162489e4e 100644 --- a/GUI/src/components/Markdowify/index.tsx +++ b/GUI/src/components/Markdowify/index.tsx @@ -76,7 +76,7 @@ const htmlLinkToMarkdown = (value: string): string => { const tempDiv = document.createElement('div'); tempDiv.innerHTML = value; const links = tempDiv.querySelectorAll('a'); - + let result = value; links.forEach((link) => { const href = link.getAttribute('href') || ''; @@ -84,7 +84,7 @@ const htmlLinkToMarkdown = (value: string): string => { const markdown = href ? `[${text}](${href})` : text; result = result.replace(link.outerHTML, markdown); }); - + return result; }; diff --git a/GUI/src/services/service-builder.ts b/GUI/src/services/service-builder.ts index 33067b203..01b2a446d 100644 --- a/GUI/src/services/service-builder.ts +++ b/GUI/src/services/service-builder.ts @@ -187,9 +187,7 @@ export const saveFlow = async ({ try { let yamlContent = getYamlContent(nodes, edges, name, description, showError); - const mcqNodes = nodes.filter( - (node) => node.data?.stepType === StepType.MultiChoiceQuestion, - ); + const mcqNodes = nodes.filter((node) => node.data?.stepType === StepType.MultiChoiceQuestion); if (mcqNodes.length > 0) { const nodesUpToFirstMcq = nodes.slice( @@ -605,9 +603,7 @@ function handleTextField( const spacePlaceholder = '___SPACE___'; const rawMessage = typeof parentNode.data.message === 'string' ? decodeHtmlEntities(parentNode.data.message) : ''; const markdownMessage = htmlToMarkdown - .translate( - rawMessage.replace('{{', '${').replace('}}', '}').replaceAll(' ', spacePlaceholder), - ) + .translate(rawMessage.replace('{{', '${').replace('}}', '}').replaceAll(' ', spacePlaceholder)) .replaceAll(spacePlaceholder, ' ') .replaceAll(/\\([-~>[\]_*#().!`=<\\])/g, String.raw`\\$1`); @@ -752,9 +748,7 @@ function handleMultiChoiceQuestion( ) { const rootServiceName = serviceName.replace(/_mcq_\d+_\d+$/, ''); parentNode.data.multiChoiceQuestion?.buttons.forEach((b) => { - b.payload = b.payload.replace(/\/[^/]*_mcq_/, `/${rootServiceName}_mcq_`); - }); return finishedFlow.set(parentStepName, { diff --git a/GUI/src/store/new-services.store.ts b/GUI/src/store/new-services.store.ts index db190b811..975209e49 100644 --- a/GUI/src/store/new-services.store.ts +++ b/GUI/src/store/new-services.store.ts @@ -304,7 +304,7 @@ const useServiceStore = create((set, get) => ({ name: 'Status Code', value: `${endpoint?.name.replaceAll(' ', '_')}_res.response.statusCodeValue`, data: `${endpoint?.name.replaceAll(' ', '_')}_res.response.statusCodeValue`, - } + }, ); const variable: EndpointResponseVariable = {