Remove mandatory task from measure

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-01-15 18:06:56 +01:00
parent 51b31f81f4
commit 3c2be844e4
13 changed files with 151 additions and 17 deletions

View File

@@ -50,6 +50,7 @@ type (
TimeEstimate **time.Duration
Deadline **time.Time
AssignedToID **gid.GID
MeasureID **gid.GID
}
)
@@ -75,6 +76,7 @@ func (utr *UpdateTaskRequest) Validate() error {
v.Check(utr.TimeEstimate, "time_estimate", validator.RangeDuration(0, 1000*time.Hour))
v.Check(utr.State, "state", validator.OneOfSlice(coredata.TaskStates()))
v.Check(utr.AssignedToID, "assigned_to_id", validator.GID(coredata.PeopleEntityType))
v.Check(utr.MeasureID, "measure_id", validator.GID(coredata.MeasureEntityType))
return v.Error()
}
@@ -275,6 +277,18 @@ func (s TaskService) Update(
}
}
if req.MeasureID != nil {
if *req.MeasureID == nil {
task.MeasureID = nil
} else {
measure := &coredata.Measure{}
if err := measure.LoadByID(ctx, conn, s.svc.scope, **req.MeasureID); err != nil {
return fmt.Errorf("cannot load measure: %w", err)
}
task.MeasureID = *req.MeasureID
}
}
task.UpdatedAt = time.Now()
if err := task.Update(ctx, conn, s.svc.scope); err != nil {

View File

@@ -3725,6 +3725,7 @@ input UpdateTaskInput {
timeEstimate: Duration @goField(omittable: true)
deadline: Datetime @goField(omittable: true)
assignedToId: ID @goField(omittable: true)
measureId: ID @goField(omittable: true)
}
input DeleteTaskInput {

View File

@@ -13945,6 +13945,7 @@ input UpdateTaskInput {
timeEstimate: Duration @goField(omittable: true)
deadline: Datetime @goField(omittable: true)
assignedToId: ID @goField(omittable: true)
measureId: ID @goField(omittable: true)
}
input DeleteTaskInput {
@@ -68042,7 +68043,7 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
asMap[k] = v
}
fieldsInOrder := [...]string{"taskId", "name", "description", "state", "timeEstimate", "deadline", "assignedToId"}
fieldsInOrder := [...]string{"taskId", "name", "description", "state", "timeEstimate", "deadline", "assignedToId", "measureId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -68098,6 +68099,13 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
return it, err
}
it.AssignedToID = graphql.OmittableOf(data)
case "measureId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("measureId"))
data, err := ec.unmarshalOID2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.MeasureID = graphql.OmittableOf(data)
}
}

View File

@@ -2307,6 +2307,7 @@ type UpdateTaskInput struct {
TimeEstimate graphql.Omittable[*time.Duration] `json:"timeEstimate,omitempty"`
Deadline graphql.Omittable[*time.Time] `json:"deadline,omitempty"`
AssignedToID graphql.Omittable[*gid.GID] `json:"assignedToId,omitempty"`
MeasureID graphql.Omittable[*gid.GID] `json:"measureId,omitempty"`
}
type UpdateTaskPayload struct {

View File

@@ -2790,7 +2790,7 @@ func (r *mutationResolver) DeleteControlSnapshotMapping(ctx context.Context, inp
func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error) {
r.MustBeAuthorized(ctx, input.OrganizationID, authz.ActionCreateTask)
prb := r.ProboService(ctx, input.MeasureID.TenantID())
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
task, err := prb.Tasks.Create(ctx, probo.CreateTaskRequest{
MeasureID: input.MeasureID,
@@ -2828,6 +2828,7 @@ func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTas
TimeEstimate: UnwrapOmittable(input.TimeEstimate),
Deadline: UnwrapOmittable(input.Deadline),
AssignedToID: UnwrapOmittable(input.AssignedToID),
MeasureID: UnwrapOmittable(input.MeasureID),
})
if err != nil {
panic(fmt.Errorf("cannot update task: %w", err))
@@ -6798,6 +6799,10 @@ func (r *taskResolver) Measure(ctx context.Context, obj *types.Task) (*types.Mea
panic(fmt.Errorf("cannot get task: %w", err))
}
if task.MeasureID == nil {
return nil, nil
}
measure, err := prb.Measures.Get(ctx, *task.MeasureID)
if err != nil {
var errNotFound *coredata.ErrMeasureNotFound

View File

@@ -1379,6 +1379,8 @@ func (r *Resolver) UpdateTaskTool(ctx context.Context, req *mcp.CallToolRequest,
State: input.State,
TimeEstimate: UnwrapOmittable(input.TimeEstimate),
Deadline: UnwrapOmittable(input.Deadline),
AssignedToID: UnwrapOmittable(input.AssignedToID),
MeasureID: UnwrapOmittable(input.MeasureID),
},
)
if err != nil {

View File

@@ -3076,6 +3076,22 @@ components:
description: No deadline
description: Deadline
go.probo.inc/mcpgen/omittable: true
assigned_to_id:
anyOf:
- $ref: "#/components/schemas/GID"
description: Assigned to person ID
- type: "null"
description: Not assigned
description: Assigned to person ID
go.probo.inc/mcpgen/omittable: true
measure_id:
anyOf:
- $ref: "#/components/schemas/GID"
description: Measure ID
- type: "null"
description: No measure
description: Measure ID
go.probo.inc/mcpgen/omittable: true
UpdateTaskOutput:
type: object

View File

@@ -169,7 +169,7 @@ var (
UpdatePeopleToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["people"],"properties":{"people":{"type":"object","required":["id","organization_id","full_name","primary_email_address","additional_email_addresses","kind","created_at","updated_at"],"properties":{"additional_email_addresses":{"type":"array","description":"Additional email addresses","items":{"type":"string","format":"string"}},"contract_end_date":{"description":"Contract end date","format":"date-time"},"contract_start_date":{"description":"Contract start date","format":"date-time"},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"full_name":{"type":"string","description":"Full name"},"id":{"type":"string","format":"string"},"kind":{"type":"string","enum":["EMPLOYEE","CONTRACTOR","SERVICE_ACCOUNT"]},"organization_id":{"type":"string","format":"string"},"position":{"description":"Position"},"primary_email_address":{"type":"string","format":"string"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`)
UpdateRiskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"category":{"type":"string","description":"Risk category"},"description":{"description":"Risk description"},"id":{"type":"string","format":"string"},"inherent_impact":{"type":"integer","description":"Inherent impact"},"inherent_likelihood":{"type":"integer","description":"Inherent likelihood"},"name":{"type":"string","description":"Risk name"},"note":{"type":"string","description":"Risk note"},"owner_id":{"description":"Owner ID","anyOf":[{"type":"string","format":"string"},{"type":"null"}]},"residual_impact":{"type":"integer","description":"Residual impact"},"residual_likelihood":{"type":"integer","description":"Residual likelihood"},"treatment":{"type":"string","enum":["MITIGATED","ACCEPTED","AVOIDED","TRANSFERRED"]}}}`)
UpdateRiskToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["risk"],"properties":{"risk":{"type":"object","required":["id","organization_id","name","category","treatment","inherent_likelihood","inherent_impact","inherent_risk_score","residual_likelihood","residual_impact","residual_risk_score","note","created_at","updated_at"],"properties":{"category":{"type":"string","description":"Risk category"},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Risk description"},"id":{"type":"string","format":"string"},"inherent_impact":{"type":"integer","description":"Inherent impact"},"inherent_likelihood":{"type":"integer","description":"Inherent likelihood"},"inherent_risk_score":{"type":"integer","description":"Inherent risk score"},"name":{"type":"string","description":"Risk name"},"note":{"type":"string","description":"Risk note"},"organization_id":{"type":"string","format":"string"},"owner_id":{"anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No owner"}]},"residual_impact":{"type":"integer","description":"Residual impact"},"residual_likelihood":{"type":"integer","description":"Residual likelihood"},"residual_risk_score":{"type":"integer","description":"Residual risk score"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"treatment":{"type":"string","enum":["MITIGATED","ACCEPTED","AVOIDED","TRANSFERRED"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`)
UpdateTaskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"deadline":{"description":"Deadline","anyOf":[{"type":"string","description":"Deadline","format":"date-time"},{"type":"null","description":"No deadline"}]},"description":{"description":"Task description"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Task name"},"state":{"description":"Task state","anyOf":[{"type":"string","enum":["TODO","DONE"]},{"type":"null","description":"No state"}]},"time_estimate":{"description":"Time estimate","anyOf":[{"type":"string","description":"A duration"},{"type":"null","description":"No time estimate"}]}}}`)
UpdateTaskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"assigned_to_id":{"description":"Assigned to person ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"Not assigned"}]},"deadline":{"description":"Deadline","anyOf":[{"type":"string","description":"Deadline","format":"date-time"},{"type":"null","description":"No deadline"}]},"description":{"description":"Task description"},"id":{"type":"string","format":"string"},"measure_id":{"description":"Measure ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No measure"}]},"name":{"type":"string","description":"Task name"},"state":{"description":"Task state","anyOf":[{"type":"string","enum":["TODO","DONE"]},{"type":"null","description":"No state"}]},"time_estimate":{"description":"Time estimate","anyOf":[{"type":"string","description":"A duration"},{"type":"null","description":"No time estimate"}]}}}`)
UpdateTaskToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["task"],"properties":{"task":{"type":"object","required":["id","organization_id","name","state","created_at","updated_at"],"properties":{"assigned_to_id":{"description":"Assigned to person ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"Not assigned"}]},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"deadline":{"description":"Deadline","anyOf":[{"type":"string","description":"Deadline","format":"date-time"},{"type":"null","description":"No deadline"}]},"description":{"description":"Task description","anyOf":[{"type":"string","description":"Task description"},{"type":"null","description":"No description"}]},"id":{"type":"string","format":"string"},"measure_id":{"description":"Measure ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No measure"}]},"name":{"type":"string","description":"Task name"},"organization_id":{"type":"string","format":"string"},"state":{"type":"string","enum":["TODO","DONE"]},"time_estimate":{"description":"Time estimate","anyOf":[{"type":"string","description":"A duration"},{"type":"null","description":"No time estimate"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`)
UpdateVendorToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"description":{"type":"string","description":"Vendor description"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Vendor name"}}}`)
UpdateVendorToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["vendor"],"properties":{"vendor":{"type":"object","required":["id","name","organization_id","created_at","updated_at"],"properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Vendor description"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Vendor name"},"organization_id":{"type":"string","format":"string"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`)
@@ -2081,12 +2081,16 @@ type UpdateRiskOutput struct {
// UpdateTaskInput represents the schema
type UpdateTaskInput struct {
// Assigned to person ID
AssignedToID mcp.Omittable[*gid.GID] `json:"assigned_to_id,omitempty"`
// Deadline
Deadline mcp.Omittable[*time.Time] `json:"deadline,omitempty"`
// Task description
Description mcp.Omittable[*string] `json:"description,omitempty"`
// Task ID
ID gid.GID `json:"id"`
// Measure ID
MeasureID mcp.Omittable[*gid.GID] `json:"measure_id,omitempty"`
// Task name
Name *string `json:"name,omitempty"`
// Task state