Changeset 0.37.15 (#227)

This commit is contained in:
2026-03-23 19:58:17 +00:00
parent b7746c3004
commit d005e8a30f
23 changed files with 1764 additions and 170 deletions

View File

@@ -510,6 +510,9 @@ type ChannelStore interface {
// CompleteWorkflow sets workflow_status='completed' and ai_mode='off'.
CompleteWorkflow(ctx context.Context, channelID string, finalStage int, stageData json.RawMessage) error
// CancelWorkflow sets workflow_status='cancelled' and ai_mode='off'. (v0.37.15)
CancelWorkflow(ctx context.Context, channelID string) error
// RejectWorkflowToStage resets current_stage (no stage_data change).
RejectWorkflowToStage(ctx context.Context, channelID string, stage int) error

View File

@@ -644,6 +644,15 @@ func (s *ChannelStore) CompleteWorkflow(ctx context.Context, channelID string, f
return err
}
func (s *ChannelStore) CancelWorkflow(ctx context.Context, channelID string) error {
_, err := DB.ExecContext(ctx, `
UPDATE channels
SET workflow_status = 'cancelled', ai_mode = 'off', last_activity_at = $1
WHERE id = $2 AND type = 'workflow'
`, time.Now().UTC(), channelID)
return err
}
func (s *ChannelStore) RejectWorkflowToStage(ctx context.Context, channelID string, stage int) error {
now := time.Now().UTC()
_, err := DB.ExecContext(ctx, `

View File

@@ -449,6 +449,56 @@ func (s *WorkflowStore) GetAssignmentChannelID(ctx context.Context, assignmentID
return channelID, err
}
// ── Lifecycle operations (v0.37.15) ──
func (s *WorkflowStore) CancelAssignmentsForChannel(ctx context.Context, channelID string) (int64, error) {
res, err := DB.ExecContext(ctx, `
UPDATE workflow_assignments
SET status = 'cancelled'
WHERE channel_id = $1 AND status IN ('unassigned', 'claimed')
`, channelID)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func (s *WorkflowStore) UnclaimAssignment(ctx context.Context, assignmentID string) (int64, error) {
res, err := DB.ExecContext(ctx, `
UPDATE workflow_assignments
SET status = 'unassigned', assigned_to = NULL, claimed_at = NULL
WHERE id = $1 AND status = 'claimed'
`, assignmentID)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func (s *WorkflowStore) ReassignAssignment(ctx context.Context, assignmentID, newUserID string) (int64, error) {
res, err := DB.ExecContext(ctx, `
UPDATE workflow_assignments
SET assigned_to = $1, claimed_at = $2
WHERE id = $3 AND status = 'claimed'
`, newUserID, time.Now().UTC(), assignmentID)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func (s *WorkflowStore) CancelAssignment(ctx context.Context, assignmentID string) (int64, error) {
res, err := DB.ExecContext(ctx, `
UPDATE workflow_assignments
SET status = 'cancelled'
WHERE id = $1 AND status IN ('unassigned', 'claimed')
`, assignmentID)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func (s *WorkflowStore) TryRoundRobin(ctx context.Context, teamID, assignmentID string) (string, error) {
// Find least-recently-assigned team member
rows, err := DB.QueryContext(ctx, `

View File

@@ -645,6 +645,15 @@ func (s *ChannelStore) CompleteWorkflow(ctx context.Context, channelID string, f
return err
}
func (s *ChannelStore) CancelWorkflow(ctx context.Context, channelID string) error {
_, err := DB.ExecContext(ctx, `
UPDATE channels
SET workflow_status = 'cancelled', ai_mode = 'off', last_activity_at = ?
WHERE id = ? AND type = 'workflow'
`, time.Now().UTC().Format(timeFmt), channelID)
return err
}
func (s *ChannelStore) RejectWorkflowToStage(ctx context.Context, channelID string, stage int) error {
now := time.Now().UTC().Format(timeFmt)
_, err := DB.ExecContext(ctx, `

View File

@@ -452,6 +452,56 @@ func (s *WorkflowStore) GetAssignmentChannelID(ctx context.Context, assignmentID
return channelID, err
}
// ── Lifecycle operations (v0.37.15) ──
func (s *WorkflowStore) CancelAssignmentsForChannel(ctx context.Context, channelID string) (int64, error) {
res, err := DB.ExecContext(ctx, `
UPDATE workflow_assignments
SET status = 'cancelled'
WHERE channel_id = ? AND status IN ('unassigned', 'claimed')
`, channelID)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func (s *WorkflowStore) UnclaimAssignment(ctx context.Context, assignmentID string) (int64, error) {
res, err := DB.ExecContext(ctx, `
UPDATE workflow_assignments
SET status = 'unassigned', assigned_to = NULL, claimed_at = NULL
WHERE id = ? AND status = 'claimed'
`, assignmentID)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func (s *WorkflowStore) ReassignAssignment(ctx context.Context, assignmentID, newUserID string) (int64, error) {
res, err := DB.ExecContext(ctx, `
UPDATE workflow_assignments
SET assigned_to = ?, claimed_at = ?
WHERE id = ? AND status = 'claimed'
`, newUserID, time.Now().UTC().Format(timeFmt), assignmentID)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func (s *WorkflowStore) CancelAssignment(ctx context.Context, assignmentID string) (int64, error) {
res, err := DB.ExecContext(ctx, `
UPDATE workflow_assignments
SET status = 'cancelled'
WHERE id = ? AND status IN ('unassigned', 'claimed')
`, assignmentID)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func (s *WorkflowStore) TryRoundRobin(ctx context.Context, teamID, assignmentID string) (string, error) {
rows, err := DB.QueryContext(ctx, `
SELECT m.user_id, COALESCE(MAX(wa.claimed_at), '1970-01-01 00:00:00') as last_claim

View File

@@ -55,6 +55,23 @@ type WorkflowStore interface {
// Returns the assigned user ID, or "" if no members available.
TryRoundRobin(ctx context.Context, teamID, assignmentID string) (string, error)
// ── Lifecycle operations (v0.37.15) ──
// CancelAssignmentsForChannel sets status='cancelled' on all
// unassigned/claimed assignments for a channel.
CancelAssignmentsForChannel(ctx context.Context, channelID string) (int64, error)
// UnclaimAssignment returns a claimed assignment to unassigned.
// Returns rows affected (0 = not claimed or not found).
UnclaimAssignment(ctx context.Context, assignmentID string) (int64, error)
// ReassignAssignment changes assigned_to on a claimed assignment.
// Returns rows affected.
ReassignAssignment(ctx context.Context, assignmentID, newUserID string) (int64, error)
// CancelAssignment sets a single assignment to cancelled.
CancelAssignment(ctx context.Context, assignmentID string) (int64, error)
// ── Review Comments (v0.35.0) ──
// GetAssignmentByID returns a single assignment by ID.