mirror of https://github.com/go-gitea/gitea.git
improvements
parent
623388cef9
commit
c2419f8c5b
|
|
@ -70,7 +70,6 @@ func (err ErrProjectNotExist) Unwrap() error {
|
||||||
type ErrProjectColumnNotExist struct {
|
type ErrProjectColumnNotExist struct {
|
||||||
ColumnID int64
|
ColumnID int64
|
||||||
ProjectID int64
|
ProjectID int64
|
||||||
Name string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsErrProjectColumnNotExist checks if an error is a ErrProjectColumnNotExist
|
// IsErrProjectColumnNotExist checks if an error is a ErrProjectColumnNotExist
|
||||||
|
|
@ -80,8 +79,8 @@ func IsErrProjectColumnNotExist(err error) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err ErrProjectColumnNotExist) Error() string {
|
func (err ErrProjectColumnNotExist) Error() string {
|
||||||
if err.ProjectID > 0 && len(err.Name) > 0 {
|
if err.ProjectID > 0 {
|
||||||
return fmt.Sprintf("project column does not exist [project_id: %d, name: %s]", err.ProjectID, err.Name)
|
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)
|
return fmt.Sprintf("project column does not exist [id: %d]", err.ColumnID)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ const (
|
||||||
WorkflowActionTypeColumn WorkflowActionType = "column" // add the item to the project's column
|
WorkflowActionTypeColumn WorkflowActionType = "column" // add the item to the project's column
|
||||||
WorkflowActionTypeAddLabels WorkflowActionType = "add_labels" // choose one or more labels
|
WorkflowActionTypeAddLabels WorkflowActionType = "add_labels" // choose one or more labels
|
||||||
WorkflowActionTypeRemoveLabels WorkflowActionType = "remove_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 {
|
type WorkflowAction struct {
|
||||||
|
|
@ -141,7 +141,7 @@ func GetWorkflowEventCapabilities() map[WorkflowEvent]WorkflowEventCapabilities
|
||||||
},
|
},
|
||||||
WorkflowEventItemColumnChanged: {
|
WorkflowEventItemColumnChanged: {
|
||||||
AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeIssueType, WorkflowFilterTypeColumn, WorkflowFilterTypeLabels},
|
AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeIssueType, WorkflowFilterTypeColumn, WorkflowFilterTypeLabels},
|
||||||
AvailableActions: []WorkflowActionType{WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels, WorkflowActionTypeClose},
|
AvailableActions: []WorkflowActionType{WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels, WorkflowActionTypeIssueState},
|
||||||
},
|
},
|
||||||
WorkflowEventCodeChangesRequested: {
|
WorkflowEventCodeChangesRequested: {
|
||||||
AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeLabels}, // only applies to pull requests
|
AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeLabels}, // only applies to pull requests
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
package projects
|
package projects
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
stdCtx "context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -25,22 +26,56 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// getFilterSummary returns a human-readable summary of the filters
|
// 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 {
|
if len(filters) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var summary strings.Builder
|
||||||
|
labelIDs := make([]int64, 0)
|
||||||
for _, filter := range filters {
|
for _, filter := range filters {
|
||||||
if filter.Type == "scope" {
|
switch filter.Type {
|
||||||
|
case project_model.WorkflowFilterTypeIssueType:
|
||||||
switch filter.Value {
|
switch filter.Value {
|
||||||
case "issue":
|
case "issue":
|
||||||
return " (Issues only)"
|
summary.WriteString(" (Issues only)")
|
||||||
case "pull_request":
|
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
|
// 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 {
|
if strValue, ok := value.(string); ok {
|
||||||
switch strings.ToLower(strValue) {
|
v := strings.ToLower(strValue)
|
||||||
case "close", "closed", "true":
|
if v == "close" || v == "reopen" {
|
||||||
actions = append(actions, project_model.WorkflowAction{
|
actions = append(actions, project_model.WorkflowAction{
|
||||||
Type: project_model.WorkflowActionTypeClose,
|
Type: project_model.WorkflowActionTypeIssueState,
|
||||||
Value: "close",
|
Value: v,
|
||||||
})
|
|
||||||
case "reopen", "open", "false":
|
|
||||||
actions = append(actions, project_model.WorkflowAction{
|
|
||||||
Type: project_model.WorkflowActionTypeClose,
|
|
||||||
Value: "reopen",
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 {
|
if len(existingWorkflows) > 0 {
|
||||||
// Add all existing workflows for this event
|
// Add all existing workflows for this event
|
||||||
for _, wf := range existingWorkflows {
|
for _, wf := range existingWorkflows {
|
||||||
filterSummary := getFilterSummary(wf.WorkflowFilters)
|
filterSummary := getFilterSummary(ctx, wf.WorkflowFilters)
|
||||||
outputWorkflows = append(outputWorkflows, &WorkflowConfig{
|
outputWorkflows = append(outputWorkflows, &WorkflowConfig{
|
||||||
ID: wf.ID,
|
ID: wf.ID,
|
||||||
EventID: strconv.FormatInt(wf.ID, 10),
|
EventID: strconv.FormatInt(wf.ID, 10),
|
||||||
|
|
@ -485,7 +508,7 @@ func WorkflowsPost(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the newly created workflow with filter summary
|
// Return the newly created workflow with filter summary
|
||||||
filterSummary := getFilterSummary(wf.WorkflowFilters)
|
filterSummary := getFilterSummary(ctx, wf.WorkflowFilters)
|
||||||
ctx.JSON(http.StatusOK, map[string]any{
|
ctx.JSON(http.StatusOK, map[string]any{
|
||||||
"success": true,
|
"success": true,
|
||||||
"workflow": map[string]any{
|
"workflow": map[string]any{
|
||||||
|
|
@ -518,7 +541,7 @@ func WorkflowsPost(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the updated workflow with filter summary
|
// Return the updated workflow with filter summary
|
||||||
filterSummary := getFilterSummary(wf.WorkflowFilters)
|
filterSummary := getFilterSummary(ctx, wf.WorkflowFilters)
|
||||||
ctx.JSON(http.StatusOK, map[string]any{
|
ctx.JSON(http.StatusOK, map[string]any{
|
||||||
"success": true,
|
"success": true,
|
||||||
"workflow": map[string]any{
|
"workflow": map[string]any{
|
||||||
|
|
|
||||||
|
|
@ -447,7 +447,7 @@ func UpdateIssueProject(ctx *context.Context) {
|
||||||
if issue.Project != nil && issue.Project.ID == projectID {
|
if issue.Project != nil && issue.Project.ID == projectID {
|
||||||
continue
|
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) {
|
if errors.Is(err, util.ErrPermissionDenied) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"code.gitea.io/gitea/services/notify"
|
"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 {
|
if err := issues_model.IssueAssignOrRemoveProject(ctx, issue, doer, projectID, 0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -424,8 +424,8 @@ func executeWorkflowActions(ctx context.Context, workflow *project_model.Workflo
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case project_model.WorkflowActionTypeClose:
|
case project_model.WorkflowActionTypeIssueState:
|
||||||
if strings.EqualFold(action.Value, "reopen") || strings.EqualFold(action.Value, "false") {
|
if strings.EqualFold(action.Value, "reopen") {
|
||||||
if issue.IsClosed {
|
if issue.IsClosed {
|
||||||
if err := issue_service.ReopenIssue(ctx, issue, user_model.NewProjectWorkflowsUser(), ""); err != nil {
|
if err := issue_service.ReopenIssue(ctx, issue, user_model.NewProjectWorkflowsUser(), ""); err != nil {
|
||||||
log.Error("ReopenIssue: %v", err)
|
log.Error("ReopenIssue: %v", err)
|
||||||
|
|
@ -433,7 +433,7 @@ func executeWorkflowActions(ctx context.Context, workflow *project_model.Workflo
|
||||||
}
|
}
|
||||||
issue.IsClosed = false
|
issue.IsClosed = false
|
||||||
}
|
}
|
||||||
} else {
|
} else if strings.EqualFold(action.Value, "close") {
|
||||||
if !issue.IsClosed {
|
if !issue.IsClosed {
|
||||||
if err := issue_service.CloseIssue(ctx, issue, user_model.NewProjectWorkflowsUser(), ""); err != nil {
|
if err := issue_service.CloseIssue(ctx, issue, user_model.NewProjectWorkflowsUser(), ""); err != nil {
|
||||||
log.Error("CloseIssue: %v", err)
|
log.Error("CloseIssue: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -977,21 +977,21 @@ onUnmounted(() => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field" v-if="hasAction('close')">
|
<div class="field" v-if="hasAction('issue_state')">
|
||||||
<label for="issue-state-action">Issue state</label>
|
<label for="issue-state-action">Issue state</label>
|
||||||
<select
|
<select
|
||||||
v-if="isInEditMode"
|
v-if="isInEditMode"
|
||||||
id="issue-state-action"
|
id="issue-state-action"
|
||||||
class="column-select"
|
class="column-select"
|
||||||
v-model="store.workflowActions.issueState"
|
v-model="store.workflowActions.issue_state"
|
||||||
>
|
>
|
||||||
<option value="">No change</option>
|
<option value="">No change</option>
|
||||||
<option value="close">Close issue</option>
|
<option value="close">Close issue</option>
|
||||||
<option value="reopen">Reopen issue</option>
|
<option value="reopen">Reopen issue</option>
|
||||||
</select>
|
</select>
|
||||||
<div v-else class="readonly-value">
|
<div v-else class="readonly-value">
|
||||||
{{ store.workflowActions.issueState === 'close' ? 'Close issue' :
|
{{ store.workflowActions.issue_state === 'close' ? 'Close issue' :
|
||||||
store.workflowActions.issueState === 'reopen' ? 'Reopen issue' : 'No change' }}
|
store.workflowActions.issue_state === 'reopen' ? 'Reopen issue' : 'No change' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue