Skip to content

Commit 9621e31

Browse files
Correct review comments
1 parent 2917df9 commit 9621e31

File tree

5 files changed

+240
-276
lines changed

5 files changed

+240
-276
lines changed

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/Topics.jsx

Lines changed: 151 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export default function Topics(props) {
138138
Object.entries(spec.channels).forEach(([key, channelObj]) => {
139139
const address = channelObj.address || `/${key}`;
140140
channelIndex[`#/channels/${key}`] = address;
141-
channelIndex[`#/channels/${key.replaceAll(/\//g, '~1')}`] = address;
141+
channelIndex[`#/channels/${key.replace(/\//g, '~1')}`] = address;
142142
channelMap[address] = channelMap[address] || {
143143
parameters: channelObj.parameters || {},
144144
...(channelObj.description && { description: channelObj.description }),
@@ -174,7 +174,7 @@ export default function Topics(props) {
174174
payload: {
175175
type: 'object',
176176
properties: {
177-
...(existing?.payload?.properties || {}),
177+
...existing?.payload?.properties,
178178
...allProperties,
179179
},
180180
},
@@ -219,43 +219,150 @@ export default function Topics(props) {
219219
};
220220
}
221221

222-
/**
223-
* Groups payload properties by message name and wires them into
224-
* components, channels, and operations.
225-
*/
226-
function wirePayloadProperties(verbInfo, channelName, newComponents, newChannels, newOperations) {
227-
if (!verbInfo.message?.payload?.properties)
228-
return { updatedComponents: newComponents, updatedChannels: newChannels };
229-
222+
function groupPayloadProperties(properties) {
230223
const byMessage = {};
231-
Object.entries(verbInfo.message.payload.properties).forEach(([compositeKey, propVal]) => {
224+
225+
Object.entries(properties).forEach(([compositeKey, propVal]) => {
232226
const msgName = propVal['x-message'] || propVal['x-operation'] || '__default__';
233-
byMessage[msgName] = byMessage[msgName] || { opName: propVal['x-operation'], props: {} };
227+
228+
if (!byMessage[msgName]) {
229+
byMessage[msgName] = { opName: propVal['x-operation'], props: {} };
230+
}
231+
234232
const originalPropName = propVal['x-prop-name'] || compositeKey;
235-
const { 'x-operation': _, 'x-message': __, 'x-prop-name': ___, ...cleanProp } = propVal;
233+
// const { 'x-operation': _, 'x-message': __, 'x-prop-name': ___, ...cleanProp } = propVal;
234+
const {
235+
'x-operation': xOperation,
236+
'x-message': xMessage,
237+
'x-prop-name': xPropName,
238+
...cleanProp
239+
} = propVal;
240+
236241
byMessage[msgName].props[originalPropName] = cleanProp;
237242
});
238-
243+
244+
return byMessage;
245+
}
246+
247+
function wireOperationMessage(opName, channelName, msgName, newOperations) {
248+
if (!opName || opName === '__default__' || !newOperations[opName]) return;
249+
250+
const ref = { $ref: `#/channels/${channelName}/messages/${msgName}` };
251+
252+
if (!newOperations[opName].messages.some((m) => m.$ref === ref.$ref)) {
253+
newOperations[opName].messages.push(ref);
254+
}
255+
}
256+
257+
function processMessageGroups(byMessage, channelName, newComponents, newChannels, newOperations) {
239258
let updatedComponents = { ...newComponents };
240259
let updatedChannels = { ...newChannels };
241-
260+
242261
Object.entries(byMessage).forEach(([msgName, { opName, props: msgProps }]) => {
243262
updatedComponents = buildUpdatedComponents(updatedComponents, msgName, msgProps);
244263
updatedChannels = buildUpdatedChannels(updatedChannels, channelName, msgName);
264+
265+
wireOperationMessage(opName, channelName, msgName, newOperations);
266+
});
267+
268+
return { updatedComponents, updatedChannels };
269+
}
270+
271+
function wirePayloadProperties(verbInfo, channelName, newComponents, newChannels, newOperations) {
272+
if (!verbInfo.message?.payload?.properties) {
273+
return { updatedComponents: newComponents, updatedChannels: newChannels };
274+
}
275+
276+
const byMessage = groupPayloadProperties(verbInfo.message.payload.properties);
277+
278+
return processMessageGroups(
279+
byMessage,
280+
channelName,
281+
newComponents,
282+
newChannels,
283+
newOperations,
284+
);
285+
}
286+
287+
function createOperationEntry(opName, action, channelName, verbInfo, originalSpec) {
288+
// const { messages: _, ...restOfOriginal } = originalSpec.operations?.[opName] || {};
289+
const { messages, ...restOfOriginal } = originalSpec.operations?.[opName] || {};
290+
291+
return {
292+
...restOfOriginal,
293+
action,
294+
channel: { $ref: `#/channels/${channelName}` },
295+
'x-auth-type': verbInfo['x-auth-type'],
296+
...(verbInfo['x-uri-mapping'] && { 'x-uri-mapping': verbInfo['x-uri-mapping'] }),
297+
...(verbInfo['x-scopes'] && { 'x-scopes': verbInfo['x-scopes'] }),
298+
messages: [],
299+
};
300+
}
301+
302+
function resolveChannel(channelAddress, channelObj, originalSpec, newChannels, addressToName) {
303+
const existingChannelName = addressToName[channelAddress];
304+
305+
if (existingChannelName) {
306+
return {
307+
channelName: existingChannelName,
308+
newChannels: {
309+
...newChannels,
310+
[existingChannelName]: {
311+
...newChannels[existingChannelName],
312+
...(channelObj.description && { description: channelObj.description }),
313+
},
314+
},
315+
};
316+
}
317+
318+
const baseChannel = channelAddress.split('/').find(s => s.length > 0) || 'channel';
319+
const randomId = crypto.randomUUID().split('-')[0];
320+
const channelName = `${baseChannel}_${randomId}`;
321+
const parametersArray = channelObj.parameters || [];
322+
323+
return {
324+
channelName,
325+
newChannels: {
326+
...newChannels,
327+
[channelName]: {
328+
address: channelAddress,
329+
...(Object.keys(parametersArray).length > 0 && { parameters: parametersArray }),
330+
},
331+
},
332+
};
333+
}
334+
335+
/**
336+
* Helper to process specific verb actions (send/receive) for a channel.
337+
* This flattens the nesting from rebuildOperations.
338+
*/
339+
function processVerbActions(context) {
340+
const {
341+
verbInfo, action, channelName,
342+
originalSpec, newOperations, newChannels, newComponents
343+
} = context;
245344

246-
// Wire into operations.{opName}.messages[]
247-
if (opName && opName !== '__default__' && newOperations[opName]) {
248-
const ref = { $ref: `#/channels/${channelName}/messages/${msgName}` };
249-
if (!newOperations[opName].messages.some((m) => m.$ref === ref.$ref)) {
250-
newOperations[opName].messages.push(ref);
251-
}
252-
}
345+
// Level 4: Extracting the operations loop into a named helper or keeping it flat here
346+
const opList = verbInfo['x-operations'] || [];
347+
opList.forEach((opName) => {
348+
newOperations[opName] = createOperationEntry(
349+
opName,
350+
action,
351+
channelName,
352+
verbInfo,
353+
originalSpec,
354+
);
253355
});
254356

255-
return { updatedComponents, updatedChannels };
357+
return wirePayloadProperties(
358+
verbInfo,
359+
channelName,
360+
newComponents,
361+
newChannels,
362+
newOperations,
363+
);
256364
}
257365

258-
// Rebuild the AsyncAPI v3 `operations` object from the UI channel map.
259366
function rebuildOperations(channelMap, originalSpec) {
260367
const newOperations = {};
261368
let newChannels = { ...originalSpec.channels };
@@ -269,53 +376,32 @@ export default function Topics(props) {
269376
}
270377

271378
Object.entries(channelMap).forEach(([channelAddress, channelObj]) => {
272-
const existingChannelName = addressToName[channelAddress];
273-
let channelName;
274-
if (existingChannelName) {
275-
channelName = existingChannelName;
276-
newChannels = {
277-
...newChannels,
278-
[existingChannelName]: {
279-
...newChannels[existingChannelName],
280-
...(channelObj.description && { description: channelObj.description }),
281-
},
282-
};
283-
} else {
284-
// Newly added channel
285-
const baseChannel = channelAddress.replace(/^\//, '').split('/')[0];
286-
const randomId = Math.random().toString(36).substring(2, 7);
287-
channelName = `${baseChannel}_${randomId}`;
288-
const parametersArray = channelObj.parameters || [];
289-
newChannels = {
290-
...newChannels,
291-
[channelName]: {
292-
address: channelAddress,
293-
...(Object.keys(parametersArray).length > 0 && { parameters: parametersArray }),
294-
},
295-
};
296-
}
379+
const resolved = resolveChannel(
380+
channelAddress,
381+
channelObj,
382+
originalSpec,
383+
newChannels,
384+
addressToName,
385+
);
386+
387+
const { channelName } = resolved;
388+
newChannels = resolved.newChannels;
297389

298390
['send', 'receive'].forEach((action) => {
299391
const verbInfo = channelObj[action];
300392
if (!verbInfo) return;
301-
// Build operation entries FIRST so newOperations[opName] exists for message wiring
302-
(verbInfo['x-operations'] || []).forEach((opName) => {
303-
const { messages: _, ...restOfOriginal } = originalSpec.operations?.[opName] || {};
304-
newOperations[opName] = {
305-
...restOfOriginal,
306-
action,
307-
channel: { $ref: `#/channels/${channelName}` },
308-
'x-auth-type': verbInfo['x-auth-type'],
309-
...(verbInfo['x-uri-mapping'] && { 'x-uri-mapping': verbInfo['x-uri-mapping'] }),
310-
...(verbInfo['x-scopes'] && { 'x-scopes': verbInfo['x-scopes'] }),
311-
messages: [],
312-
};
393+
const result = processVerbActions({
394+
verbInfo,
395+
action,
396+
channelName,
397+
originalSpec,
398+
newOperations,
399+
newChannels,
400+
newComponents,
313401
});
314402

315-
// Wire payload properties and capture updated components/channels
316-
({ updatedComponents: newComponents, updatedChannels: newChannels } = wirePayloadProperties(
317-
verbInfo, channelName, newComponents, newChannels, newOperations,
318-
));
403+
newComponents = result.updatedComponents;
404+
newChannels = result.updatedChannels;
319405
});
320406
});
321407
return { newOperations, newChannels, newComponents };

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Resources/components/AddOperation.jsx

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -276,24 +276,6 @@ function AddOperation(props) {
276276
defaultMessage: 'Enter URI pattern',
277277
});
278278
};
279-
const getOperationHelpertext = () => {
280-
if (isAsyncV3 && isAsyncAPI) {
281-
return intl.formatMessage({
282-
id: 'Apis.Details.Resources.components.AddOperation.channel.address',
283-
defaultMessage: 'Enter Channel Address',
284-
});
285-
}
286-
if (isAsyncAPI) {
287-
return intl.formatMessage({
288-
id: 'Apis.Details.Resources.components.AddOperation.operation.target.topic.name',
289-
defaultMessage: 'Enter topic name',
290-
});
291-
}
292-
return intl.formatMessage({
293-
id: 'Apis.Details.Resources.components.AddOperation.operation.target.uri.pattern',
294-
defaultMessage: 'Enter URI pattern',
295-
});
296-
};
297279

298280

299281
return (
@@ -347,7 +329,7 @@ function AddOperation(props) {
347329
renderValue={(verbs) => {
348330
const remaining = [];
349331
const verbElements = verbs.map((verb, index) => {
350-
if (index < 2) return <VerbElement isButton verb={verb} />;
332+
if (index < 2) return <VerbElement key={verb} isButton verb={verb} />;
351333
remaining.push(verb.toUpperCase());
352334
return null;
353335
});
@@ -417,7 +399,7 @@ function AddOperation(props) {
417399
value: !isWebSub && !isAsyncAPI && !value.startsWith('/') ? `/${value}` : value,
418400
})}
419401
placeholder={getOperationPlaceholder()}
420-
helperText={newOperations.error || getOperationHelpertext()}
402+
helperText={newOperations.error || getOperationPlaceholder()}
421403
fullWidth
422404
margin='dense'
423405
variant='outlined'

0 commit comments

Comments
 (0)