merge()

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 };
              });
            },