diff --git a/models/project/project.go b/models/project/project.go index 81b5ac0cde..e423a8025b 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -70,7 +70,6 @@ func (err ErrProjectNotExist) Unwrap() error { type ErrProjectColumnNotExist struct { ColumnID int64 ProjectID int64 - Name string } // IsErrProjectColumnNotExist checks if an error is a ErrProjectColumnNotExist @@ -80,8 +79,8 @@ func IsErrProjectColumnNotExist(err error) bool { } func (err ErrProjectColumnNotExist) Error() string { - if err.ProjectID > 0 && len(err.Name) > 0 { - return fmt.Sprintf("project column does not exist [project_id: %d, name: %s]", err.ProjectID, err.Name) + if err.ProjectID > 0 { + return fmt.Sprintf("project column does not exist [project_id: %d, column_id: %d]", err.ProjectID, err.ColumnID) } return fmt.Sprintf("project column does not exist [id: %d]", err.ColumnID) } diff --git a/models/project/workflows.go b/models/project/workflows.go index 2259dcac41..48e88c6c56 100644 --- a/models/project/workflows.go +++ b/models/project/workflows.go @@ -106,7 +106,7 @@ const ( WorkflowActionTypeColumn WorkflowActionType = "column" // add the item to the project's column WorkflowActionTypeAddLabels WorkflowActionType = "add_labels" // choose one or more labels WorkflowActionTypeRemoveLabels WorkflowActionType = "remove_labels" // choose one or more labels - WorkflowActionTypeClose WorkflowActionType = "close" // close the issue + WorkflowActionTypeIssueState WorkflowActionType = "issue_state" // change the issue state (reopen/close) ) type WorkflowAction struct { @@ -141,7 +141,7 @@ func GetWorkflowEventCapabilities() map[WorkflowEvent]WorkflowEventCapabilities }, WorkflowEventItemColumnChanged: { AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeIssueType, WorkflowFilterTypeColumn, WorkflowFilterTypeLabels}, - AvailableActions: []WorkflowActionType{WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels, WorkflowActionTypeClose}, + AvailableActions: []WorkflowActionType{WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels, WorkflowActionTypeIssueState}, }, WorkflowEventCodeChangesRequested: { AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeLabels}, // only applies to pull requests diff --git a/routers/web/projects/workflows.go b/routers/web/projects/workflows.go index 9c3a23ac3e..a8bd0bda20 100644 --- a/routers/web/projects/workflows.go +++ b/routers/web/projects/workflows.go @@ -4,6 +4,7 @@ package projects import ( + stdCtx "context" "errors" "io" "net/http" @@ -25,22 +26,56 @@ var ( ) // getFilterSummary returns a human-readable summary of the filters -func getFilterSummary(filters []project_model.WorkflowFilter) string { +func getFilterSummary(ctx stdCtx.Context, filters []project_model.WorkflowFilter) string { if len(filters) == 0 { return "" } + var summary strings.Builder + labelIDs := make([]int64, 0) for _, filter := range filters { - if filter.Type == "scope" { + switch filter.Type { + case project_model.WorkflowFilterTypeIssueType: switch filter.Value { case "issue": - return " (Issues only)" + summary.WriteString(" (Issues only)") case "pull_request": - return " (Pull requests only)" + summary.WriteString(" (Pull requests only)") + } + case project_model.WorkflowFilterTypeColumn: + columnID, _ := strconv.ParseInt(filter.Value, 10, 64) + if columnID <= 0 { + continue + } + col, err := project_model.GetColumn(ctx, columnID) + if err != nil { + log.Error("GetColumn: %v", err) + continue + } + summary.WriteString(" (Column: " + col.Title + ")") + case project_model.WorkflowFilterTypeLabels: + labelID, _ := strconv.ParseInt(filter.Value, 10, 64) + if labelID > 0 { + labelIDs = append(labelIDs, labelID) } } } - return "" + if len(labelIDs) > 0 { + labels, err := issues_model.GetLabelsByIDs(ctx, labelIDs) + if err != nil { + log.Error("GetLabelsByIDs: %v", err) + } else { + summary.WriteString(" (Labels: ") + for i, label := range labels { + summary.WriteString(label.Name) + if i < len(labels)-1 { + summary.WriteString(", ") + } + } + summary.WriteString(")") + } + } + return summary.String() } // convertFormToFilters converts form filters to WorkflowFilter objects @@ -133,28 +168,16 @@ func convertFormToActions(formActions map[string]any) []project_model.WorkflowAc } } } - case "issueState": + case "issue_state": if strValue, ok := value.(string); ok { - switch strings.ToLower(strValue) { - case "close", "closed", "true": - actions = append(actions, project_model.WorkflowAction{ - Type: project_model.WorkflowActionTypeClose, - Value: "close", - }) - case "reopen", "open", "false": + v := strings.ToLower(strValue) + if v == "close" || v == "reopen" { actions = append(actions, project_model.WorkflowAction{ - Type: project_model.WorkflowActionTypeClose, - Value: "reopen", + Type: project_model.WorkflowActionTypeIssueState, + Value: v, }) } } - case "closeIssue": - if boolValue, ok := value.(bool); ok && boolValue { - actions = append(actions, project_model.WorkflowAction{ - Type: project_model.WorkflowActionTypeClose, - Value: "close", - }) - } } } @@ -216,7 +239,7 @@ func WorkflowsEvents(ctx *context.Context) { if len(existingWorkflows) > 0 { // Add all existing workflows for this event for _, wf := range existingWorkflows { - filterSummary := getFilterSummary(wf.WorkflowFilters) + filterSummary := getFilterSummary(ctx, wf.WorkflowFilters) outputWorkflows = append(outputWorkflows, &WorkflowConfig{ ID: wf.ID, EventID: strconv.FormatInt(wf.ID, 10), @@ -485,7 +508,7 @@ func WorkflowsPost(ctx *context.Context) { } // Return the newly created workflow with filter summary - filterSummary := getFilterSummary(wf.WorkflowFilters) + filterSummary := getFilterSummary(ctx, wf.WorkflowFilters) ctx.JSON(http.StatusOK, map[string]any{ "success": true, "workflow": map[string]any{ @@ -518,7 +541,7 @@ func WorkflowsPost(ctx *context.Context) { } // Return the updated workflow with filter summary - filterSummary := getFilterSummary(wf.WorkflowFilters) + filterSummary := getFilterSummary(ctx, wf.WorkflowFilters) ctx.JSON(http.StatusOK, map[string]any{ "success": true, "workflow": map[string]any{ diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index eb1af2d1a2..a002dddf1d 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -447,7 +447,7 @@ func UpdateIssueProject(ctx *context.Context) { if issue.Project != nil && issue.Project.ID == projectID { continue } - if err := issues_servie.IssueAssignOrRemoveProject(ctx, issue, ctx.Doer, projectID, 0); err != nil { + if err := issues_servie.AssignOrRemoveProject(ctx, issue, ctx.Doer, projectID, 0); err != nil { if errors.Is(err, util.ErrPermissionDenied) { continue } diff --git a/services/issue/project.go b/services/issue/project.go index f818a869b0..eb6c4b9f25 100644 --- a/services/issue/project.go +++ b/services/issue/project.go @@ -12,7 +12,7 @@ import ( "code.gitea.io/gitea/services/notify" ) -func IssueAssignOrRemoveProject(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, projectID int64, position int) error { +func AssignOrRemoveProject(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, projectID int64, position int) error { if err := issues_model.IssueAssignOrRemoveProject(ctx, issue, doer, projectID, 0); err != nil { return err } diff --git a/services/projects/workflow_notifier.go b/services/projects/workflow_notifier.go index 812c9f5bd2..a48bb7e556 100644 --- a/services/projects/workflow_notifier.go +++ b/services/projects/workflow_notifier.go @@ -424,8 +424,8 @@ func executeWorkflowActions(ctx context.Context, workflow *project_model.Workflo } continue } - case project_model.WorkflowActionTypeClose: - if strings.EqualFold(action.Value, "reopen") || strings.EqualFold(action.Value, "false") { + case project_model.WorkflowActionTypeIssueState: + if strings.EqualFold(action.Value, "reopen") { if issue.IsClosed { if err := issue_service.ReopenIssue(ctx, issue, user_model.NewProjectWorkflowsUser(), ""); err != nil { log.Error("ReopenIssue: %v", err) @@ -433,7 +433,7 @@ func executeWorkflowActions(ctx context.Context, workflow *project_model.Workflo } issue.IsClosed = false } - } else { + } else if strings.EqualFold(action.Value, "close") { if !issue.IsClosed { if err := issue_service.CloseIssue(ctx, issue, user_model.NewProjectWorkflowsUser(), ""); err != nil { log.Error("CloseIssue: %v", err) diff --git a/web_src/js/components/projects/ProjectWorkflow.vue b/web_src/js/components/projects/ProjectWorkflow.vue index 68fb28671b..306286e6d3 100644 --- a/web_src/js/components/projects/ProjectWorkflow.vue +++ b/web_src/js/components/projects/ProjectWorkflow.vue @@ -977,21 +977,21 @@ onUnmounted(() => { -
+
- {{ store.workflowActions.issueState === 'close' ? 'Close issue' : - store.workflowActions.issueState === 'reopen' ? 'Reopen issue' : 'No change' }} + {{ store.workflowActions.issue_state === 'close' ? 'Close issue' : + store.workflowActions.issue_state === 'reopen' ? 'Reopen issue' : 'No change' }}