in app/assets/javascripts/graphql_shared/issuable_client.js [154:284]
merge(existing = [], incoming, context) {
if (existing.length === 0) {
return incoming;
}
return existing.map((existingWidget) => {
const incomingWidget = incoming.find(
(w) => w.type && w.type === existingWidget.type,
);
// we want to concat next page of awardEmoji to the existing ones
if (incomingWidget?.type === WIDGET_TYPE_AWARD_EMOJI && context.variables.after) {
// concatPagination won't work because we were placing new widget here so we have to do this manually
return {
...incomingWidget,
awardEmoji: {
...incomingWidget.awardEmoji,
nodes: [
...existingWidget.awardEmoji.nodes,
...incomingWidget.awardEmoji.nodes,
],
},
};
}
// we want to concat next page of discussions to the existing ones
if (incomingWidget?.type === WIDGET_TYPE_NOTES && context.variables.after) {
// concatPagination won't work because we were placing new widget here so we have to do this manually
return {
...incomingWidget,
discussions: {
...incomingWidget.discussions,
nodes: [
...existingWidget.discussions.nodes,
...incomingWidget.discussions.nodes,
],
},
};
}
// we want to concat next page of children work items within Hierarchy widget to the existing ones
if (
incomingWidget?.type === WIDGET_TYPE_HIERARCHY &&
context.variables.endCursor &&
incomingWidget.children?.nodes
) {
// concatPagination won't work because we were placing new widget here so we have to do this manually
return {
...incomingWidget,
children: {
...incomingWidget.children,
nodes: [...existingWidget.children.nodes, ...incomingWidget.children.nodes],
},
};
}
// we want to concat next page of vulnerabilities work items within Vulnerabilities widget to the existing ones
if (
incomingWidget?.type === WIDGET_TYPE_VULNERABILITIES &&
context.variables.after &&
incomingWidget.relatedVulnerabilities?.nodes
) {
// concatPagination won't work because we were placing new widget here so we have to do this manually
return {
...incomingWidget,
relatedVulnerabilities: {
...incomingWidget.relatedVulnerabilities,
nodes: [
...existingWidget.relatedVulnerabilities.nodes,
...incomingWidget.relatedVulnerabilities.nodes,
],
},
};
}
// this ensures that we don’t override linkedItems.workItem when updating parent
if (incomingWidget?.type === WIDGET_TYPE_LINKED_ITEMS) {
if (!incomingWidget.linkedItems) {
return existingWidget;
}
const incomingNodes = incomingWidget.linkedItems?.nodes || [];
const existingNodes = existingWidget.linkedItems?.nodes || [];
const resultNodes = incomingNodes.map((incomingNode) => {
const existingNode =
existingNodes.find((n) => n.linkId === incomingNode.linkId) ?? {};
return { ...existingNode, ...incomingNode };
});
// we only set up linked items when the widget is present and has `workItem` property
if (context.variables.iid) {
const items = resultNodes
.filter((node) => node.workItem)
// normally we would only get a `__ref` for nested properties but we need to extract the full work item
// eslint-disable-next-line no-underscore-dangle
.map((node) => context.cache.extract()[node.workItem.__ref]);
// Ensure that any existing linked items are retained
const existingLinkedItems = linkedItems();
linkedItems({
...existingLinkedItems,
[`${context.variables.fullPath}:${context.variables.iid}`]: items,
});
}
return {
...incomingWidget,
linkedItems: {
...incomingWidget.linkedItems,
nodes: resultNodes,
},
};
}
if (existingWidget?.type === WIDGET_TYPE_ASSIGNEES && context.variables.id) {
const workItemAssignees = existingWidget.assignees?.nodes || [];
const users = workItemAssignees.map(
// eslint-disable-next-line no-underscore-dangle
(user) => context.cache.extract()[user.__ref],
);
const existingAssignees = currentAssignees();
currentAssignees({
...existingAssignees,
[`${context.variables.id}`]: users,
});
}
return { ...existingWidget, ...incomingWidget };
});
},