Inherit relations from child to parents

📘

How to apply this rule?

When two Stories are connected, connect their Features

{
  "pipeline": [
    {
      "type": "source:targetprocess:EntityChanged",
      "entityTypes": [
        "Relation"
      ],
      "modifications": {
        "created": true,
        "deleted": false,
        "updated": false
      }
    },
    {
      "or": [
        {
          "and": [
            {
              "value": {
                "type": "constant",
                "value": "UserStory"
              },
              "target": {
                "name": "Name",
                "type": "field",
                "target": {
                  "name": "EntityType",
                  "type": "field",
                  "target": {
                    "name": "Inbound",
                    "type": "field",
                    "target": {
                      "type": "pipelineBlockOutput"
                    }
                  }
                }
              },
              "operator": {
                "type": "is"
              }
            },
            {
              "value": {
                "type": "constant",
                "value": "UserStory"
              },
              "target": {
                "name": "Name",
                "type": "field",
                "target": {
                  "name": "EntityType",
                  "type": "field",
                  "target": {
                    "name": "Outbound",
                    "type": "field",
                    "target": {
                      "type": "pipelineBlockOutput"
                    }
                  }
                }
              },
              "operator": {
                "type": "is"
              }
            },
            {
              "value": null,
              "target": {
                "name": "Feature",
                "type": "field",
                "target": {
                  "name": "Inbound",
                  "type": "field",
                  "target": {
                    "type": "pipelineBlockOutput"
                  }
                }
              },
              "operator": {
                "type": "exists"
              }
            },
            {
              "value": null,
              "target": {
                "name": "Feature",
                "type": "field",
                "target": {
                  "name": "Outbound",
                  "type": "field",
                  "target": {
                    "type": "pipelineBlockOutput"
                  }
                }
              },
              "operator": {
                "type": "exists"
              }
            },
            {
              "value": {
                "name": "Feature",
                "type": "field",
                "target": {
                  "name": "Outbound",
                  "type": "field",
                  "target": {
                    "type": "pipelineBlockOutput"
                  }
                }
              },
              "target": {
                "name": "Feature",
                "type": "field",
                "target": {
                  "name": "Inbound",
                  "type": "field",
                  "target": {
                    "type": "pipelineBlockOutput"
                  }
                }
              },
              "operator": {
                "type": "is not"
              }
            }
          ]
        }
      ],
      "type": "filter:Relational"
    },
    {
      "type": "filter:JavaScript",
      "script": "const api = context.getService(\"targetprocess/api/v2\");\nconst count = await api.queryAsync(\"Relation\", {\n  result: \"count\",\n  where: `SlaveFeature.UserStories.Count(Id=${args.Current.Outbound.Id}) > 0 and ` +\n    `MasterFeature.UserStories.Count(Id=${args.Current.Inbound.Id}) > 0`\n});\n\nreturn count == 0;\n\n"
    },
    {
      "type": "action:targetprocess:CreateEntity",
      "fields": {
        "Inbound": {
          "name": "Id",
          "type": "field",
          "target": {
            "name": "Feature",
            "type": "field",
            "target": {
              "name": "Inbound",
              "type": "field",
              "target": {
                "type": "pipelineBlockOutput"
              }
            }
          }
        },
        "Outbound": {
          "name": "Id",
          "type": "field",
          "target": {
            "name": "Feature",
            "type": "field",
            "target": {
              "name": "Outbound",
              "type": "field",
              "target": {
                "type": "pipelineBlockOutput"
              }
            }
          }
        },
        "RelationType": {
          "name": "Id",
          "type": "field",
          "target": {
            "name": "RelationType",
            "type": "field",
            "target": {
              "type": "pipelineBlockOutput"
            }
          }
        }
      },
      "entityType": {
        "type": "constant",
        "value": "Relation"
      }
    }
  ]
}

When Story is added to a Feature, connect this Feature to the Features of related Stories

[
  {
    "type": "source:targetprocess:EntityChanged",
    "entityTypes": [
      "UserStory"
    ],
    "modifications": {
      "created": true,
      "deleted": false,
      "updated": [
        "Feature"
      ]
    }
  },
  {
    "or": [
      {
        "and": [
          {
            "value": null,
            "target": {
              "name": "Feature",
              "type": "field",
              "target": {
                "type": "pipelineBlockOutput"
              }
            },
            "operator": {
              "type": "exists"
            }
          }
        ]
      }
    ],
    "type": "filter:Relational"
  },
  {
    "type": "action:JavaScript",
    "script": "const childType = args.ResourceType;\nconst parentType = \"Feature\";\nconst directions = [\"inbound\", \"outbound\"];\n\nconst leftRelation = { \"inbound\": \"master\", \"outbound\": \"slave\" };\nconst rigthRelation = { \"inbound\": \"slave\" , \"outbound\": \"master\" };\n\nconst api = context.getService(\"targetprocess/api/v2\");\nconst getRelations = function () {\n  return directions.map(direction => {\n    const left = leftRelation[direction];\n    const rigth = rigthRelation[direction];\n    return `${direction}:` +\n      `${left}Relations.Where(${left}.EntityType.Name=\"${childType}\" and ${left}${childType}.${parentType} != null).` +\n      `Select({${left}:${left}${childType}.${parentType}.Id,${rigth}:${rigth}${childType}.${parentType}.Id,type:RelationType.Id}),` +\n      `${parentType}${direction}:` +\n      `${parentType}.${left}Relations.Where(${left}.EntityType.Name=\"${parentType}\").` +\n      `Select({${left}:${left}.Id,${rigth}:${rigth}.Id})`\n  }).join(\",\");\n}\n\nconst children = await api.queryAsync(args.ResourceType, {\n  select: `{${getRelations()}}`,\n  where: \"id=\" + args.ResourceId\n});\nif (!children || !children.length) { return; }\nconst child = children[0];\nconsole.log(JSON.stringify(child));\n\nconst commands = [];\nfor (let direction of directions) {\n  for (let relation of child[direction]) {\n    const left = leftRelation[direction];\n    const rigth = rigthRelation[direction];\n    let search = child[parentType + direction].filter(r => {\n      return r[left] === relation[left] && r[rigth] === relation[rigth];;\n    });\n    if (!search || !search.length) {\n      child[parentType + direction].push({\n        [left]: relation[left],\n        [rigth]: relation[rigth]\n      });\n      commands.push({\n        command: \"targetprocess:CreateResource\",\n        payload: {\n          resourceType: \"Relation\",\n          fields: {\n            [left]: { Id: relation[left] },\n            [rigth]: { Id: relation[rigth] },\n            RelationType: { Id: relation.type }\n          }\n        }\n      });\n    }\n  }\n}\nreturn commands;"
  }
]