mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-08 01:16:45 +08:00
* MUL-8120 feat(workflows): record workflow owner and let owners edit their workflows Any workspace member may now create a workflow and becomes its owner. Editing, deleting and changing handoffs is open to the owner and to workspace owners/admins. Default has no owner and stays admin-only. Copying a workflow for one project now also requires managing that project. Migration 585 adds issue_workflow.owner_id and backfills existing named workflows with the workspace's earliest owner. Co-authored-by: multica-agent <[email protected]> * MUL-8120 feat(workflows): mirror owner-based workflow permissions in the UI Members can create and duplicate workflows; the editor, column handoff and flow panel are editable by the workflow's owner and admins. The save-for-this-project option only shows to admins and the project lead. Co-authored-by: multica-agent <[email protected]> * MUL-8120 fix(workflows): only admins add statuses through workflow writes Workflow create/update could add statuses to the shared workspace catalog without a role check. Non-admins now get 403 status_create_forbidden when a step names a status that does not exist; reusing a status by key or by name stays open. Co-authored-by: multica-agent <[email protected]> * MUL-8120 fix(workflows): hide new-status for members in the workflow editor Members pick from existing statuses only. A template that needs statuses the workspace lacks shows which ones and keeps Save disabled until they are removed or an admin adds them. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: multica-agent <[email protected]>
659 lines
18 KiB
Go
659 lines
18 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
// source: issue_workflow.sql
|
|
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const countProjectIssuesByStatus = `-- name: CountProjectIssuesByStatus :many
|
|
SELECT status, COUNT(*)::bigint AS issue_count
|
|
FROM issue
|
|
WHERE workspace_id = $1::uuid
|
|
AND project_id = ANY($2::uuid[])
|
|
GROUP BY status
|
|
ORDER BY status
|
|
`
|
|
|
|
type CountProjectIssuesByStatusParams struct {
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
ProjectIds []pgtype.UUID `json:"project_ids"`
|
|
}
|
|
|
|
type CountProjectIssuesByStatusRow struct {
|
|
Status string `json:"status"`
|
|
IssueCount int64 `json:"issue_count"`
|
|
}
|
|
|
|
// Status census for a workflow switch or step removal, including terminal
|
|
// issues: every issue of the project must end on a status its workflow lists.
|
|
func (q *Queries) CountProjectIssuesByStatus(ctx context.Context, arg CountProjectIssuesByStatusParams) ([]CountProjectIssuesByStatusRow, error) {
|
|
rows, err := q.db.Query(ctx, countProjectIssuesByStatus, arg.WorkspaceID, arg.ProjectIds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []CountProjectIssuesByStatusRow{}
|
|
for rows.Next() {
|
|
var i CountProjectIssuesByStatusRow
|
|
if err := rows.Scan(&i.Status, &i.IssueCount); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const createDefaultIssueWorkflow = `-- name: CreateDefaultIssueWorkflow :many
|
|
INSERT INTO issue_workflow (workspace_id, name, description, initial_status_key, steps, is_default)
|
|
VALUES (
|
|
$1::uuid,
|
|
'Default',
|
|
'',
|
|
'todo',
|
|
$2::jsonb,
|
|
true
|
|
)
|
|
ON CONFLICT (workspace_id) WHERE is_default DO NOTHING
|
|
RETURNING id, workspace_id, name, description, initial_status_key, steps, created_at, updated_at, is_default, owner_id
|
|
`
|
|
|
|
type CreateDefaultIssueWorkflowParams struct {
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
Steps []byte `json:"steps"`
|
|
}
|
|
|
|
// Returns no row when another request created the Default first.
|
|
func (q *Queries) CreateDefaultIssueWorkflow(ctx context.Context, arg CreateDefaultIssueWorkflowParams) ([]IssueWorkflow, error) {
|
|
rows, err := q.db.Query(ctx, createDefaultIssueWorkflow, arg.WorkspaceID, arg.Steps)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []IssueWorkflow{}
|
|
for rows.Next() {
|
|
var i IssueWorkflow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Name,
|
|
&i.Description,
|
|
&i.InitialStatusKey,
|
|
&i.Steps,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.IsDefault,
|
|
&i.OwnerID,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const createIssueWorkflow = `-- name: CreateIssueWorkflow :one
|
|
INSERT INTO issue_workflow (workspace_id, name, description, initial_status_key, steps, owner_id)
|
|
VALUES (
|
|
$1::uuid,
|
|
$2::text,
|
|
$3::text,
|
|
$4::text,
|
|
$5::jsonb,
|
|
$6::uuid
|
|
)
|
|
RETURNING id, workspace_id, name, description, initial_status_key, steps, created_at, updated_at, is_default, owner_id
|
|
`
|
|
|
|
type CreateIssueWorkflowParams struct {
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
InitialStatusKey string `json:"initial_status_key"`
|
|
Steps []byte `json:"steps"`
|
|
OwnerID pgtype.UUID `json:"owner_id"`
|
|
}
|
|
|
|
func (q *Queries) CreateIssueWorkflow(ctx context.Context, arg CreateIssueWorkflowParams) (IssueWorkflow, error) {
|
|
row := q.db.QueryRow(ctx, createIssueWorkflow,
|
|
arg.WorkspaceID,
|
|
arg.Name,
|
|
arg.Description,
|
|
arg.InitialStatusKey,
|
|
arg.Steps,
|
|
arg.OwnerID,
|
|
)
|
|
var i IssueWorkflow
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Name,
|
|
&i.Description,
|
|
&i.InitialStatusKey,
|
|
&i.Steps,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.IsDefault,
|
|
&i.OwnerID,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const deleteIssueWorkflow = `-- name: DeleteIssueWorkflow :execrows
|
|
DELETE FROM issue_workflow
|
|
WHERE id = $1::uuid
|
|
AND workspace_id = $2::uuid
|
|
AND NOT is_default
|
|
`
|
|
|
|
type DeleteIssueWorkflowParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
}
|
|
|
|
func (q *Queries) DeleteIssueWorkflow(ctx context.Context, arg DeleteIssueWorkflowParams) (int64, error) {
|
|
result, err := q.db.Exec(ctx, deleteIssueWorkflow, arg.ID, arg.WorkspaceID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected(), nil
|
|
}
|
|
|
|
const deleteIssueWorkflowsForWorkspace = `-- name: DeleteIssueWorkflowsForWorkspace :exec
|
|
DELETE FROM issue_workflow WHERE workspace_id = $1::uuid
|
|
`
|
|
|
|
// No foreign keys by project rule, so workspace teardown cleans up here.
|
|
func (q *Queries) DeleteIssueWorkflowsForWorkspace(ctx context.Context, workspaceID pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, deleteIssueWorkflowsForWorkspace, workspaceID)
|
|
return err
|
|
}
|
|
|
|
const getDefaultIssueWorkflow = `-- name: GetDefaultIssueWorkflow :one
|
|
SELECT id, workspace_id, name, description, initial_status_key, steps, created_at, updated_at, is_default, owner_id FROM issue_workflow
|
|
WHERE workspace_id = $1::uuid
|
|
AND is_default
|
|
`
|
|
|
|
func (q *Queries) GetDefaultIssueWorkflow(ctx context.Context, workspaceID pgtype.UUID) (IssueWorkflow, error) {
|
|
row := q.db.QueryRow(ctx, getDefaultIssueWorkflow, workspaceID)
|
|
var i IssueWorkflow
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Name,
|
|
&i.Description,
|
|
&i.InitialStatusKey,
|
|
&i.Steps,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.IsDefault,
|
|
&i.OwnerID,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getIssueWorkflow = `-- name: GetIssueWorkflow :one
|
|
SELECT id, workspace_id, name, description, initial_status_key, steps, created_at, updated_at, is_default, owner_id FROM issue_workflow
|
|
WHERE id = $1::uuid
|
|
AND workspace_id = $2::uuid
|
|
`
|
|
|
|
type GetIssueWorkflowParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
}
|
|
|
|
func (q *Queries) GetIssueWorkflow(ctx context.Context, arg GetIssueWorkflowParams) (IssueWorkflow, error) {
|
|
row := q.db.QueryRow(ctx, getIssueWorkflow, arg.ID, arg.WorkspaceID)
|
|
var i IssueWorkflow
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Name,
|
|
&i.Description,
|
|
&i.InitialStatusKey,
|
|
&i.Steps,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.IsDefault,
|
|
&i.OwnerID,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const listIssueWorkflowNamesUsingStatusKey = `-- name: ListIssueWorkflowNamesUsingStatusKey :many
|
|
SELECT name FROM issue_workflow
|
|
WHERE workspace_id = $1::uuid
|
|
AND NOT is_default
|
|
AND steps @> jsonb_build_array(jsonb_build_object('status_key', $2::text))
|
|
ORDER BY lower(name)
|
|
`
|
|
|
|
type ListIssueWorkflowNamesUsingStatusKeyParams struct {
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
StatusKey string `json:"status_key"`
|
|
}
|
|
|
|
// Archive guard for the status catalog: a status a workflow still lists cannot
|
|
// be retired, or that workflow's projects would lose a column.
|
|
func (q *Queries) ListIssueWorkflowNamesUsingStatusKey(ctx context.Context, arg ListIssueWorkflowNamesUsingStatusKeyParams) ([]string, error) {
|
|
rows, err := q.db.Query(ctx, listIssueWorkflowNamesUsingStatusKey, arg.WorkspaceID, arg.StatusKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []string{}
|
|
for rows.Next() {
|
|
var name string
|
|
if err := rows.Scan(&name); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, name)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listIssueWorkflows = `-- name: ListIssueWorkflows :many
|
|
|
|
SELECT id, workspace_id, name, description, initial_status_key, steps, created_at, updated_at, is_default, owner_id FROM issue_workflow
|
|
WHERE workspace_id = $1::uuid
|
|
ORDER BY is_default DESC, lower(name), created_at, id
|
|
`
|
|
|
|
// Project workflows (MUL-7420). A workflow selects and orders statuses from
|
|
// the workspace's issue_status catalog. Projects opt in through
|
|
// project.workflow_id; a project without one uses the workspace's Default
|
|
// workflow row. Each step also stores who an issue entering it is handed to.
|
|
func (q *Queries) ListIssueWorkflows(ctx context.Context, workspaceID pgtype.UUID) ([]IssueWorkflow, error) {
|
|
rows, err := q.db.Query(ctx, listIssueWorkflows, workspaceID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []IssueWorkflow{}
|
|
for rows.Next() {
|
|
var i IssueWorkflow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Name,
|
|
&i.Description,
|
|
&i.InitialStatusKey,
|
|
&i.Steps,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.IsDefault,
|
|
&i.OwnerID,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listNamedIssueWorkflowSteps = `-- name: ListNamedIssueWorkflowSteps :many
|
|
SELECT steps FROM issue_workflow
|
|
WHERE workspace_id = $1::uuid
|
|
AND NOT is_default
|
|
`
|
|
|
|
// The steps of every workflow except Default, for the Default snapshot.
|
|
func (q *Queries) ListNamedIssueWorkflowSteps(ctx context.Context, workspaceID pgtype.UUID) ([][]byte, error) {
|
|
rows, err := q.db.Query(ctx, listNamedIssueWorkflowSteps, workspaceID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := [][]byte{}
|
|
for rows.Next() {
|
|
var steps []byte
|
|
if err := rows.Scan(&steps); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, steps)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listProjectsUsingDefaultIssueWorkflow = `-- name: ListProjectsUsingDefaultIssueWorkflow :many
|
|
SELECT id, workspace_id, title, description, icon, status, lead_type, lead_id, created_at, updated_at, priority, start_date, due_date, workflow_id FROM project
|
|
WHERE workspace_id = $1::uuid
|
|
AND workflow_id IS NULL
|
|
ORDER BY created_at, id
|
|
`
|
|
|
|
func (q *Queries) ListProjectsUsingDefaultIssueWorkflow(ctx context.Context, workspaceID pgtype.UUID) ([]Project, error) {
|
|
rows, err := q.db.Query(ctx, listProjectsUsingDefaultIssueWorkflow, workspaceID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []Project{}
|
|
for rows.Next() {
|
|
var i Project
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Title,
|
|
&i.Description,
|
|
&i.Icon,
|
|
&i.Status,
|
|
&i.LeadType,
|
|
&i.LeadID,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.Priority,
|
|
&i.StartDate,
|
|
&i.DueDate,
|
|
&i.WorkflowID,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listProjectsUsingIssueWorkflow = `-- name: ListProjectsUsingIssueWorkflow :many
|
|
SELECT id, workspace_id, title, description, icon, status, lead_type, lead_id, created_at, updated_at, priority, start_date, due_date, workflow_id FROM project
|
|
WHERE workspace_id = $1::uuid
|
|
AND workflow_id = $2::uuid
|
|
ORDER BY created_at, id
|
|
`
|
|
|
|
type ListProjectsUsingIssueWorkflowParams struct {
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
WorkflowID pgtype.UUID `json:"workflow_id"`
|
|
}
|
|
|
|
func (q *Queries) ListProjectsUsingIssueWorkflow(ctx context.Context, arg ListProjectsUsingIssueWorkflowParams) ([]Project, error) {
|
|
rows, err := q.db.Query(ctx, listProjectsUsingIssueWorkflow, arg.WorkspaceID, arg.WorkflowID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []Project{}
|
|
for rows.Next() {
|
|
var i Project
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Title,
|
|
&i.Description,
|
|
&i.Icon,
|
|
&i.Status,
|
|
&i.LeadType,
|
|
&i.LeadID,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.Priority,
|
|
&i.StartDate,
|
|
&i.DueDate,
|
|
&i.WorkflowID,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const lockProjectForWorkflowChange = `-- name: LockProjectForWorkflowChange :one
|
|
SELECT id, workspace_id, title, description, icon, status, lead_type, lead_id, created_at, updated_at, priority, start_date, due_date, workflow_id FROM project
|
|
WHERE id = $1::uuid
|
|
AND workspace_id = $2::uuid
|
|
FOR UPDATE
|
|
`
|
|
|
|
type LockProjectForWorkflowChangeParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
}
|
|
|
|
// Serializes concurrent workflow switches of one project.
|
|
func (q *Queries) LockProjectForWorkflowChange(ctx context.Context, arg LockProjectForWorkflowChangeParams) (Project, error) {
|
|
row := q.db.QueryRow(ctx, lockProjectForWorkflowChange, arg.ID, arg.WorkspaceID)
|
|
var i Project
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Title,
|
|
&i.Description,
|
|
&i.Icon,
|
|
&i.Status,
|
|
&i.LeadType,
|
|
&i.LeadID,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.Priority,
|
|
&i.StartDate,
|
|
&i.DueDate,
|
|
&i.WorkflowID,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const remapProjectIssueStatus = `-- name: RemapProjectIssueStatus :many
|
|
UPDATE issue AS i SET
|
|
status = $1::text,
|
|
duplicate_of_issue_id = NULL,
|
|
position = (
|
|
SELECT COALESCE(MIN(target.position), 0) - 1
|
|
FROM issue AS target
|
|
WHERE target.workspace_id = i.workspace_id
|
|
AND target.status = $1::text
|
|
),
|
|
revision = i.revision + 1,
|
|
last_activity_at = GREATEST(COALESCE(i.last_activity_at, i.updated_at), now()),
|
|
updated_at = now()
|
|
WHERE i.workspace_id = $2::uuid
|
|
AND i.project_id = ANY($3::uuid[])
|
|
AND i.status = $4::text
|
|
AND i.status <> $1::text
|
|
RETURNING i.id, i.workspace_id, i.title, i.description, i.status, i.priority, i.assignee_type, i.assignee_id, i.creator_type, i.creator_id, i.parent_issue_id, i.acceptance_criteria, i.context_refs, i.position, i.due_date, i.created_at, i.updated_at, i.number, i.project_id, i.origin_type, i.origin_id, i.first_executed_at, i.start_date, i.metadata, i.stage, i.properties, i.revision, i.last_activity_at, i.triage_state, i.duplicate_of_issue_id
|
|
`
|
|
|
|
type RemapProjectIssueStatusParams struct {
|
|
ToStatus string `json:"to_status"`
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
ProjectIds []pgtype.UUID `json:"project_ids"`
|
|
FromStatus string `json:"from_status"`
|
|
}
|
|
|
|
// Moves every issue of the given projects from one status to another as part
|
|
// of an administrative workflow change. Mirrors UpdateIssueStatus: the issue
|
|
// is re-ranked to the top of its new column, the revision advances, and a
|
|
// duplicate mark only survives cancelled -> cancelled (never the case here,
|
|
// because from and to differ). It deliberately touches nothing else, so it
|
|
// never hands an issue off or starts a run.
|
|
func (q *Queries) RemapProjectIssueStatus(ctx context.Context, arg RemapProjectIssueStatusParams) ([]Issue, error) {
|
|
rows, err := q.db.Query(ctx, remapProjectIssueStatus,
|
|
arg.ToStatus,
|
|
arg.WorkspaceID,
|
|
arg.ProjectIds,
|
|
arg.FromStatus,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []Issue{}
|
|
for rows.Next() {
|
|
var i Issue
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Title,
|
|
&i.Description,
|
|
&i.Status,
|
|
&i.Priority,
|
|
&i.AssigneeType,
|
|
&i.AssigneeID,
|
|
&i.CreatorType,
|
|
&i.CreatorID,
|
|
&i.ParentIssueID,
|
|
&i.AcceptanceCriteria,
|
|
&i.ContextRefs,
|
|
&i.Position,
|
|
&i.DueDate,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.Number,
|
|
&i.ProjectID,
|
|
&i.OriginType,
|
|
&i.OriginID,
|
|
&i.FirstExecutedAt,
|
|
&i.StartDate,
|
|
&i.Metadata,
|
|
&i.Stage,
|
|
&i.Properties,
|
|
&i.Revision,
|
|
&i.LastActivityAt,
|
|
&i.TriageState,
|
|
&i.DuplicateOfIssueID,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const removeStatusFromDefaultIssueWorkflow = `-- name: RemoveStatusFromDefaultIssueWorkflow :exec
|
|
UPDATE issue_workflow SET
|
|
steps = COALESCE((
|
|
SELECT jsonb_agg(step ORDER BY ord)
|
|
FROM jsonb_array_elements(steps) WITH ORDINALITY AS s(step, ord)
|
|
WHERE step->>'status_key' <> $1::text
|
|
), '[]'::jsonb),
|
|
updated_at = now()
|
|
WHERE workspace_id = $2::uuid
|
|
AND is_default
|
|
AND steps @> jsonb_build_array(jsonb_build_object('status_key', $1::text))
|
|
`
|
|
|
|
type RemoveStatusFromDefaultIssueWorkflowParams struct {
|
|
StatusKey string `json:"status_key"`
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
}
|
|
|
|
// An archived status leaves Default with it; Default never blocks an archive.
|
|
func (q *Queries) RemoveStatusFromDefaultIssueWorkflow(ctx context.Context, arg RemoveStatusFromDefaultIssueWorkflowParams) error {
|
|
_, err := q.db.Exec(ctx, removeStatusFromDefaultIssueWorkflow, arg.StatusKey, arg.WorkspaceID)
|
|
return err
|
|
}
|
|
|
|
const setProjectWorkflow = `-- name: SetProjectWorkflow :one
|
|
UPDATE project SET
|
|
workflow_id = $1::uuid,
|
|
updated_at = now()
|
|
WHERE id = $2::uuid
|
|
AND workspace_id = $3::uuid
|
|
RETURNING id, workspace_id, title, description, icon, status, lead_type, lead_id, created_at, updated_at, priority, start_date, due_date, workflow_id
|
|
`
|
|
|
|
type SetProjectWorkflowParams struct {
|
|
WorkflowID pgtype.UUID `json:"workflow_id"`
|
|
ID pgtype.UUID `json:"id"`
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
}
|
|
|
|
func (q *Queries) SetProjectWorkflow(ctx context.Context, arg SetProjectWorkflowParams) (Project, error) {
|
|
row := q.db.QueryRow(ctx, setProjectWorkflow, arg.WorkflowID, arg.ID, arg.WorkspaceID)
|
|
var i Project
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Title,
|
|
&i.Description,
|
|
&i.Icon,
|
|
&i.Status,
|
|
&i.LeadType,
|
|
&i.LeadID,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.Priority,
|
|
&i.StartDate,
|
|
&i.DueDate,
|
|
&i.WorkflowID,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const updateIssueWorkflow = `-- name: UpdateIssueWorkflow :one
|
|
UPDATE issue_workflow SET
|
|
name = $1::text,
|
|
description = $2::text,
|
|
initial_status_key = $3::text,
|
|
steps = $4::jsonb,
|
|
updated_at = now()
|
|
WHERE id = $5::uuid
|
|
AND workspace_id = $6::uuid
|
|
RETURNING id, workspace_id, name, description, initial_status_key, steps, created_at, updated_at, is_default, owner_id
|
|
`
|
|
|
|
type UpdateIssueWorkflowParams struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
InitialStatusKey string `json:"initial_status_key"`
|
|
Steps []byte `json:"steps"`
|
|
ID pgtype.UUID `json:"id"`
|
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
|
}
|
|
|
|
func (q *Queries) UpdateIssueWorkflow(ctx context.Context, arg UpdateIssueWorkflowParams) (IssueWorkflow, error) {
|
|
row := q.db.QueryRow(ctx, updateIssueWorkflow,
|
|
arg.Name,
|
|
arg.Description,
|
|
arg.InitialStatusKey,
|
|
arg.Steps,
|
|
arg.ID,
|
|
arg.WorkspaceID,
|
|
)
|
|
var i IssueWorkflow
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.WorkspaceID,
|
|
&i.Name,
|
|
&i.Description,
|
|
&i.InitialStatusKey,
|
|
&i.Steps,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.IsDefault,
|
|
&i.OwnerID,
|
|
)
|
|
return i, err
|
|
}
|