Scope sub-third-parties per parent

Replace the many-to-many junction table with a direct
parent_third_party_id foreign key on third_parties. Each
sub-third-party now belongs to exactly one parent, making
duplicates across parents independent entities.

Replace the firstLevel boolean with an integer level field
(1 = direct, 2+ = parent level + 1) to support arbitrary
nesting depth.

Remove the createThirdPartyThirdPartyMapping and
deleteThirdPartyThirdPartyMapping mutations, the CLI
link/unlink commands, and the corresponding MCP tools.
Creating a child third party now just requires passing
parentThirdPartyId on the existing createThirdParty mutation.

The frontend walks the parentThirdParty chain to build
display names like "Name (Ancestor1/Ancestor2)" and shows
clickable ancestor links on the detail page.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-05-29 16:22:54 +02:00
parent ec858e58df
commit b6781d3de0
36 changed files with 1276 additions and 1192 deletions

View File

@@ -73,7 +73,7 @@ func (r *Resolver) ListThirdPartiesTool(ctx context.Context, req *mcp.CallToolRe
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
thirdPartyFilter := coredata.NewThirdPartyFilter(nil, input.FirstLevel, nil)
thirdPartyFilter := coredata.NewThirdPartyFilter(nil, input.Level, nil)
page, err := prb.ThirdParties.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor, thirdPartyFilter)
if err != nil {
@@ -6215,32 +6215,6 @@ func (r *Resolver) MoveTrackerResourceToCategoryTool(ctx context.Context, req *m
return nil, types.MoveTrackerResourceToCategoryOutput{TrackerResource: types.NewTrackerResource(result.TrackerResource)}, nil
}
func (r *Resolver) CreateThirdPartyThirdPartyMappingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateThirdPartyThirdPartyMappingInput) (*mcp.CallToolResult, types.CreateThirdPartyThirdPartyMappingOutput, error) {
scope, err := r.Authorize(ctx, input.ParentThirdPartyID, probo.ActionThirdPartyRelationCreate)
if err != nil {
return nil, types.CreateThirdPartyThirdPartyMappingOutput{}, err
}
if _, err := r.proboSvc.ThirdParties.CreateThirdPartyMapping(ctx, scope, input.ParentThirdPartyID, input.ChildThirdPartyID); err != nil {
return nil, types.CreateThirdPartyThirdPartyMappingOutput{}, fmt.Errorf("cannot create third party mapping: %w", err)
}
return nil, types.CreateThirdPartyThirdPartyMappingOutput{}, nil
}
func (r *Resolver) DeleteThirdPartyThirdPartyMappingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteThirdPartyThirdPartyMappingInput) (*mcp.CallToolResult, types.DeleteThirdPartyThirdPartyMappingOutput, error) {
scope, err := r.Authorize(ctx, input.ParentThirdPartyID, probo.ActionThirdPartyRelationDelete)
if err != nil {
return nil, types.DeleteThirdPartyThirdPartyMappingOutput{}, err
}
if err := r.proboSvc.ThirdParties.DeleteThirdPartyMapping(ctx, scope, input.ParentThirdPartyID, input.ChildThirdPartyID); err != nil {
return nil, types.DeleteThirdPartyThirdPartyMappingOutput{}, fmt.Errorf("cannot delete third party mapping: %w", err)
}
return nil, types.DeleteThirdPartyThirdPartyMappingOutput{}, nil
}
func (r *Resolver) ListChildThirdPartiesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListChildThirdPartiesInput) (*mcp.CallToolResult, types.ListChildThirdPartiesOutput, error) {
scope, err := r.Authorize(ctx, input.ParentThirdPartyID, probo.ActionThirdPartyRelationList)
if err != nil {