Add measure-document linking
Introduce the ability to link measures to documents, following the existing pattern used by controls and risks. This includes: - Database migration for measures_documents join table - Coredata MeasureDocument struct with insert/delete operations - Document service methods for listing/counting by measure ID - Measure service CreateDocumentMapping/DeleteDocumentMapping methods - Cleanup of measure-document mappings on document archive - GraphQL mutations, inputs, payloads, and Measure.documents field - DocumentConnection.TotalCount support for measure resolver - MCP linkMeasure/unlinkMeasure updated to support documents - MCP listMeasureDocuments tool - Frontend MeasureDocumentsTab with LinkedDocumentsCard integration - Authorization actions for measure document mapping - E2e tests for measure document mapping Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -2597,6 +2597,11 @@ func (r *Resolver) LinkMeasureTool(ctx context.Context, req *mcp.CallToolRequest
|
||||
if _, _, err := svc.Risks.CreateMeasureMapping(ctx, input.ResourceID, input.MeasureID); err != nil {
|
||||
return nil, types.LinkMeasureOutput{}, fmt.Errorf("failed to link measure to risk: %w", err)
|
||||
}
|
||||
case coredata.DocumentEntityType:
|
||||
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingCreate)
|
||||
if _, _, err := svc.Measures.CreateDocumentMapping(ctx, input.MeasureID, input.ResourceID); err != nil {
|
||||
return nil, types.LinkMeasureOutput{}, fmt.Errorf("failed to link measure to document: %w", err)
|
||||
}
|
||||
default:
|
||||
return nil, types.LinkMeasureOutput{}, fmt.Errorf("unsupported resource type for measure linking: entity type %d", input.ResourceID.EntityType())
|
||||
}
|
||||
@@ -2618,6 +2623,11 @@ func (r *Resolver) UnlinkMeasureTool(ctx context.Context, req *mcp.CallToolReque
|
||||
if _, _, err := svc.Risks.DeleteMeasureMapping(ctx, input.ResourceID, input.MeasureID); err != nil {
|
||||
return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("failed to unlink measure from risk: %w", err)
|
||||
}
|
||||
case coredata.DocumentEntityType:
|
||||
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingDelete)
|
||||
if _, _, err := svc.Measures.DeleteDocumentMapping(ctx, input.MeasureID, input.ResourceID); err != nil {
|
||||
return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("failed to unlink measure from document: %w", err)
|
||||
}
|
||||
default:
|
||||
return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("unsupported resource type for measure unlinking: entity type %d", input.ResourceID.EntityType())
|
||||
}
|
||||
@@ -3873,3 +3883,29 @@ func (r *Resolver) PublishMinorDocumentVersionTool(ctx context.Context, req *mcp
|
||||
DocumentVersion: types.NewDocumentVersion(documentVersion),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *Resolver) ListMeasureDocumentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMeasureDocumentsInput) (*mcp.CallToolResult, types.ListMeasureDocumentsOutput, error) {
|
||||
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureGet)
|
||||
|
||||
prb := r.ProboService(ctx, input.MeasureID)
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: coredata.DocumentOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if input.OrderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: input.OrderBy.Field,
|
||||
Direction: input.OrderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||
|
||||
docPage, err := prb.Documents.ListForMeasureID(ctx, input.MeasureID, cursor, coredata.NewDocumentFilter(nil))
|
||||
if err != nil {
|
||||
return nil, types.ListMeasureDocumentsOutput{}, fmt.Errorf("failed to list measure documents: %w", err)
|
||||
}
|
||||
|
||||
return nil, types.NewListMeasureDocumentsOutput(docPage), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user