mirror of
https://github.com/go-gitea/gitea.git
synced 2026-03-06 23:02:06 +01:00
improvements
This commit is contained in:
parent
c2419f8c5b
commit
903d605fe1
@ -64,7 +64,7 @@ func (we WorkflowEvent) LangKey() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (we WorkflowEvent) UUID() string {
|
||||
func (we WorkflowEvent) EventID() string {
|
||||
switch we {
|
||||
case WorkflowEventItemOpened:
|
||||
return "item_opened"
|
||||
@ -90,9 +90,9 @@ func (we WorkflowEvent) UUID() string {
|
||||
type WorkflowFilterType string
|
||||
|
||||
const (
|
||||
WorkflowFilterTypeIssueType WorkflowFilterType = "issue_type" // issue, pull_request, etc.
|
||||
WorkflowFilterTypeColumn WorkflowFilterType = "column" // target column for item_column_changed event
|
||||
WorkflowFilterTypeLabels WorkflowFilterType = "labels" // filter by issue/PR labels
|
||||
WorkflowFilterTypeIssueType WorkflowFilterType = "issue_type" // issue, pull_request, etc.
|
||||
WorkflowFilterTypeColumn WorkflowFilterType = "target_column" // target column for item_column_changed event
|
||||
WorkflowFilterTypeLabels WorkflowFilterType = "labels" // filter by issue/PR labels
|
||||
)
|
||||
|
||||
type WorkflowFilter struct {
|
||||
|
||||
@ -52,7 +52,7 @@ func getFilterSummary(ctx stdCtx.Context, filters []project_model.WorkflowFilter
|
||||
log.Error("GetColumn: %v", err)
|
||||
continue
|
||||
}
|
||||
summary.WriteString(" (Column: " + col.Title + ")")
|
||||
summary.WriteString(" (Target Column: " + col.Title + ")")
|
||||
case project_model.WorkflowFilterTypeLabels:
|
||||
labelID, _ := strconv.ParseInt(filter.Value, 10, 64)
|
||||
if labelID > 0 {
|
||||
@ -243,7 +243,7 @@ func WorkflowsEvents(ctx *context.Context) {
|
||||
outputWorkflows = append(outputWorkflows, &WorkflowConfig{
|
||||
ID: wf.ID,
|
||||
EventID: strconv.FormatInt(wf.ID, 10),
|
||||
DisplayName: string(ctx.Tr(wf.WorkflowEvent.LangKey())) + filterSummary,
|
||||
DisplayName: string(ctx.Tr(wf.WorkflowEvent.LangKey())),
|
||||
BaseEventType: string(wf.WorkflowEvent),
|
||||
WorkflowEvent: string(wf.WorkflowEvent),
|
||||
Capabilities: capabilities[event],
|
||||
@ -258,7 +258,7 @@ func WorkflowsEvents(ctx *context.Context) {
|
||||
// Add placeholder for creating new workflow
|
||||
outputWorkflows = append(outputWorkflows, &WorkflowConfig{
|
||||
ID: 0,
|
||||
EventID: event.UUID(),
|
||||
EventID: event.EventID(),
|
||||
DisplayName: string(ctx.Tr(event.LangKey())),
|
||||
BaseEventType: string(event),
|
||||
WorkflowEvent: string(event),
|
||||
@ -514,7 +514,7 @@ func WorkflowsPost(ctx *context.Context) {
|
||||
"workflow": map[string]any{
|
||||
"id": wf.ID,
|
||||
"event_id": strconv.FormatInt(wf.ID, 10),
|
||||
"display_name": string(ctx.Tr(wf.WorkflowEvent.LangKey())) + filterSummary,
|
||||
"display_name": string(ctx.Tr(wf.WorkflowEvent.LangKey())),
|
||||
"filters": wf.WorkflowFilters,
|
||||
"actions": wf.WorkflowActions,
|
||||
"filter_summary": filterSummary,
|
||||
|
||||
@ -55,7 +55,7 @@ func (m *workflowNotifier) NewIssue(ctx context.Context, issue *issues_model.Iss
|
||||
// Find workflows for the ItemOpened event
|
||||
for _, workflow := range workflows {
|
||||
if workflow.WorkflowEvent == project_model.WorkflowEventItemOpened {
|
||||
fireIssueWorkflow(ctx, workflow, issue)
|
||||
fireIssueWorkflow(ctx, workflow, issue, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,7 +92,7 @@ func (m *workflowNotifier) IssueChangeStatus(ctx context.Context, doer *user_mod
|
||||
// Find workflows for the specific event
|
||||
for _, workflow := range workflows {
|
||||
if workflow.WorkflowEvent == workflowEvent {
|
||||
fireIssueWorkflow(ctx, workflow, issue)
|
||||
fireIssueWorkflow(ctx, workflow, issue, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,7 +124,7 @@ func (*workflowNotifier) IssueChangeProjects(ctx context.Context, doer *user_mod
|
||||
// Find workflows for the ItemOpened event
|
||||
for _, workflow := range workflows {
|
||||
if workflow.WorkflowEvent == project_model.WorkflowEventItemAddedToProject {
|
||||
fireIssueWorkflow(ctx, workflow, issue)
|
||||
fireIssueWorkflow(ctx, workflow, issue, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,7 +158,7 @@ func (*workflowNotifier) IssueChangeProjectColumn(ctx context.Context, doer *use
|
||||
// Find workflows for the ItemColumnChanged event
|
||||
for _, workflow := range workflows {
|
||||
if workflow.WorkflowEvent == project_model.WorkflowEventItemColumnChanged {
|
||||
fireIssueWorkflowWithColumn(ctx, workflow, issue, newColumnID)
|
||||
fireIssueWorkflow(ctx, workflow, issue, newColumnID)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,7 +192,7 @@ func (*workflowNotifier) MergePullRequest(ctx context.Context, doer *user_model.
|
||||
// Find workflows for the PullRequestMerged event
|
||||
for _, workflow := range workflows {
|
||||
if workflow.WorkflowEvent == project_model.WorkflowEventPullRequestMerged {
|
||||
fireIssueWorkflow(ctx, workflow, issue)
|
||||
fireIssueWorkflow(ctx, workflow, issue, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,14 +231,12 @@ func (*workflowNotifier) PullRequestReview(ctx context.Context, pr *issues_model
|
||||
for _, workflow := range workflows {
|
||||
if (workflow.WorkflowEvent == project_model.WorkflowEventCodeChangesRequested && review.Type == issues_model.ReviewTypeReject) ||
|
||||
(workflow.WorkflowEvent == project_model.WorkflowEventCodeReviewApproved && review.Type == issues_model.ReviewTypeApprove) {
|
||||
fireIssueWorkflow(ctx, workflow, issue)
|
||||
fireIssueWorkflow(ctx, workflow, issue, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fireIssueWorkflowWithColumn fires a workflow for an issue with a specific column ID
|
||||
// This is used for ItemColumnChanged events where we need to check the target column
|
||||
func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Workflow, issue *issues_model.Issue, columnID int64) {
|
||||
func fireIssueWorkflow(ctx context.Context, workflow *project_model.Workflow, issue *issues_model.Issue, columnID int64) {
|
||||
if !workflow.Enabled {
|
||||
return
|
||||
}
|
||||
@ -249,6 +247,15 @@ func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Wo
|
||||
return
|
||||
}
|
||||
|
||||
if !matchWorkflowsFilters(workflow, issue, columnID) {
|
||||
return
|
||||
}
|
||||
|
||||
executeWorkflowActions(ctx, workflow, issue)
|
||||
}
|
||||
|
||||
// matchWorkflowsFilters checks if the issue matches all filters of the workflow
|
||||
func matchWorkflowsFilters(workflow *project_model.Workflow, issue *issues_model.Issue, columnID int64) bool {
|
||||
for _, filter := range workflow.WorkflowFilters {
|
||||
switch filter.Type {
|
||||
case project_model.WorkflowFilterTypeIssueType:
|
||||
@ -258,10 +265,10 @@ func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Wo
|
||||
}
|
||||
// Filter value can be "issue" or "pull_request"
|
||||
if filter.Value == "issue" && issue.IsPull {
|
||||
return
|
||||
return false
|
||||
}
|
||||
if filter.Value == "pull_request" && !issue.IsPull {
|
||||
return
|
||||
return false
|
||||
}
|
||||
case project_model.WorkflowFilterTypeColumn:
|
||||
// If filter value is empty, match all columns
|
||||
@ -271,18 +278,18 @@ func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Wo
|
||||
filterColumnID, _ := strconv.ParseInt(filter.Value, 10, 64)
|
||||
if filterColumnID == 0 {
|
||||
log.Error("Invalid column ID: %s", filter.Value)
|
||||
return
|
||||
return false
|
||||
}
|
||||
// For column changed event, check against the new column ID
|
||||
if columnID != filterColumnID {
|
||||
return
|
||||
if columnID > 0 && columnID != filterColumnID {
|
||||
return false
|
||||
}
|
||||
case project_model.WorkflowFilterTypeLabels:
|
||||
// Check if issue has the specified label
|
||||
labelID, _ := strconv.ParseInt(filter.Value, 10, 64)
|
||||
if labelID == 0 {
|
||||
log.Error("Invalid label ID: %s", filter.Value)
|
||||
return
|
||||
return false
|
||||
}
|
||||
// Check if issue has this label
|
||||
hasLabel := false
|
||||
@ -293,85 +300,14 @@ func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Wo
|
||||
}
|
||||
}
|
||||
if !hasLabel {
|
||||
return
|
||||
return false
|
||||
}
|
||||
default:
|
||||
log.Error("Unsupported filter type: %s", filter.Type)
|
||||
return
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
executeWorkflowActions(ctx, workflow, issue)
|
||||
}
|
||||
|
||||
func fireIssueWorkflow(ctx context.Context, workflow *project_model.Workflow, issue *issues_model.Issue) {
|
||||
if !workflow.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
// Load issue labels for labels filter
|
||||
if err := issue.LoadLabels(ctx); err != nil {
|
||||
log.Error("LoadLabels: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, filter := range workflow.WorkflowFilters {
|
||||
switch filter.Type {
|
||||
case project_model.WorkflowFilterTypeIssueType:
|
||||
// If filter value is empty, match all types
|
||||
if filter.Value == "" {
|
||||
continue
|
||||
}
|
||||
// Filter value can be "issue" or "pull_request"
|
||||
if filter.Value == "issue" && issue.IsPull {
|
||||
return
|
||||
}
|
||||
if filter.Value == "pull_request" && !issue.IsPull {
|
||||
return
|
||||
}
|
||||
case project_model.WorkflowFilterTypeColumn:
|
||||
// If filter value is empty, match all columns
|
||||
if filter.Value == "" {
|
||||
continue
|
||||
}
|
||||
columnID, _ := strconv.ParseInt(filter.Value, 10, 64)
|
||||
if columnID == 0 {
|
||||
log.Error("Invalid column ID: %s", filter.Value)
|
||||
return
|
||||
}
|
||||
issueProjectColumnID, err := issue.ProjectColumnID(ctx)
|
||||
if err != nil {
|
||||
log.Error("Issue.ProjectColumnID: %v", err)
|
||||
return
|
||||
}
|
||||
if issueProjectColumnID != columnID {
|
||||
return
|
||||
}
|
||||
case project_model.WorkflowFilterTypeLabels:
|
||||
// Check if issue has the specified label
|
||||
labelID, _ := strconv.ParseInt(filter.Value, 10, 64)
|
||||
if labelID == 0 {
|
||||
log.Error("Invalid label ID: %s", filter.Value)
|
||||
return
|
||||
}
|
||||
// Check if issue has this label
|
||||
hasLabel := false
|
||||
for _, label := range issue.Labels {
|
||||
if label.ID == labelID {
|
||||
hasLabel = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasLabel {
|
||||
return
|
||||
}
|
||||
default:
|
||||
log.Error("Unsupported filter type: %s", filter.Type)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
executeWorkflowActions(ctx, workflow, issue)
|
||||
return true
|
||||
}
|
||||
|
||||
func executeWorkflowActions(ctx context.Context, workflow *project_model.Workflow, issue *issues_model.Issue) {
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
{{template "repo/header" .}}
|
||||
<div class="ui container padded">
|
||||
<div class="tw-flex tw-justify-between tw-items-center tw-mb-4">
|
||||
<a class="ui" href="{{.ProjectLink}}">{{svg "octicon-arrow-left"}} {{ctx.Locale.Tr "projects.workflows"}} {{.Project.Title}}</a>
|
||||
</div>
|
||||
<a class="ui" href="{{.ProjectLink}}">{{svg "octicon-arrow-left"}} {{ctx.Locale.Tr "projects.workflows"}} {{.Project.Title}}</a>
|
||||
</div>
|
||||
</div>
|
||||
{{template "projects/workflows" .}}
|
||||
</div>
|
||||
|
||||
@ -829,11 +829,11 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field" v-if="hasFilter('column')">
|
||||
<div class="field" v-if="hasFilter('target_column')">
|
||||
<label>When moved to column</label>
|
||||
<select
|
||||
v-if="isInEditMode"
|
||||
v-model="store.workflowFilters.column"
|
||||
v-model="store.workflowFilters.target_column"
|
||||
class="column-select"
|
||||
>
|
||||
<option value="">Any column</option>
|
||||
@ -842,7 +842,7 @@ onUnmounted(() => {
|
||||
</option>
|
||||
</select>
|
||||
<div v-else class="readonly-value">
|
||||
{{ store.projectColumns.find(c => String(c.id) === store.workflowFilters.column)?.title || 'Any column' }}
|
||||
{{ store.projectColumns.find(c => String(c.id) === store.workflowFilters.target_column)?.title || 'Any column' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import {showInfoToast, showErrorToast} from '../../modules/toast.ts';
|
||||
|
||||
type WorkflowFiltersState = {
|
||||
issue_type: string;
|
||||
column: string;
|
||||
target_column: string;
|
||||
labels: string[];
|
||||
};
|
||||
|
||||
@ -14,7 +14,7 @@ type WorkflowActionsState = {
|
||||
column: string;
|
||||
add_labels: string[];
|
||||
remove_labels: string[];
|
||||
issueState: WorkflowIssueStateAction;
|
||||
issue_state: WorkflowIssueStateAction;
|
||||
};
|
||||
|
||||
type WorkflowDraftState = {
|
||||
@ -22,12 +22,12 @@ type WorkflowDraftState = {
|
||||
actions: WorkflowActionsState;
|
||||
};
|
||||
|
||||
const createDefaultFilters = (): WorkflowFiltersState => ({issue_type: '', column: '', labels: []});
|
||||
const createDefaultActions = (): WorkflowActionsState => ({column: '', add_labels: [], remove_labels: [], issueState: ''});
|
||||
const createDefaultFilters = (): WorkflowFiltersState => ({issue_type: '', target_column: '', labels: []});
|
||||
const createDefaultActions = (): WorkflowActionsState => ({column: '', add_labels: [], remove_labels: [], issue_state: ''});
|
||||
|
||||
const cloneFilters = (filters: WorkflowFiltersState): WorkflowFiltersState => ({
|
||||
issue_type: filters.issue_type,
|
||||
column: filters.column,
|
||||
target_column: filters.target_column,
|
||||
labels: Array.from(filters.labels),
|
||||
});
|
||||
|
||||
@ -35,7 +35,7 @@ const cloneActions = (actions: WorkflowActionsState): WorkflowActionsState => ({
|
||||
column: actions.column,
|
||||
add_labels: Array.from(actions.add_labels),
|
||||
remove_labels: Array.from(actions.remove_labels),
|
||||
issueState: actions.issueState,
|
||||
issue_state: actions.issue_state,
|
||||
});
|
||||
|
||||
export function createWorkflowStore(props: {projectLink: string, eventID: string}) {
|
||||
@ -107,21 +107,19 @@ export function createWorkflowStore(props: {projectLink: string, eventID: string
|
||||
|
||||
// Find the workflow from existing workflowEvents
|
||||
const workflow = store.workflowEvents.find((e) => e.event_id === eventId);
|
||||
console.log('[WorkflowStore] loadWorkflowData - eventId:', eventId);
|
||||
console.log('[WorkflowStore] loadWorkflowData - found workflow:', workflow);
|
||||
|
||||
// Load existing configuration from the workflow data
|
||||
// Convert backend filter format to frontend format
|
||||
const frontendFilters = {issue_type: '', column: '', labels: []};
|
||||
const frontendFilters = {issue_type: '', target_column: '', labels: []};
|
||||
// Convert backend action format to frontend format
|
||||
const frontendActions: WorkflowActionsState = {column: '', add_labels: [], remove_labels: [], issueState: ''};
|
||||
const frontendActions: WorkflowActionsState = {column: '', add_labels: [], remove_labels: [], issue_state: ''};
|
||||
|
||||
if (workflow?.filters && Array.isArray(workflow.filters)) {
|
||||
for (const filter of workflow.filters) {
|
||||
if (filter.type === 'issue_type') {
|
||||
frontendFilters.issue_type = filter.value;
|
||||
} else if (filter.type === 'column') {
|
||||
frontendFilters.column = filter.value;
|
||||
} else if (filter.type === 'target_column') {
|
||||
frontendFilters.target_column = filter.value;
|
||||
} else if (filter.type === 'labels') {
|
||||
frontendFilters.labels.push(filter.value);
|
||||
}
|
||||
@ -140,9 +138,9 @@ export function createWorkflowStore(props: {projectLink: string, eventID: string
|
||||
frontendActions.remove_labels.push(action.value);
|
||||
} else if (action.type === 'close') {
|
||||
if (action.value === 'reopen' || action.value === 'false') {
|
||||
frontendActions.issueState = 'reopen';
|
||||
frontendActions.issue_state = 'reopen';
|
||||
} else if (action.value === 'true' || action.value === 'close') {
|
||||
frontendActions.issueState = 'close';
|
||||
frontendActions.issue_state = 'close';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,9 +158,9 @@ export function createWorkflowStore(props: {projectLink: string, eventID: string
|
||||
frontendActions.remove_labels.push(action.value);
|
||||
} else if (action.type === 'close') {
|
||||
if (action.value === 'reopen' || action.value === 'false') {
|
||||
frontendActions.issueState = 'reopen';
|
||||
frontendActions.issue_state = 'reopen';
|
||||
} else if (action.value === 'true' || action.value === 'close') {
|
||||
frontendActions.issueState = 'close';
|
||||
frontendActions.issue_state = 'close';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -261,15 +259,15 @@ export function createWorkflowStore(props: {projectLink: string, eventID: string
|
||||
|
||||
// Convert backend data to frontend format and update form
|
||||
// Use the selectedWorkflow which now points to the reloaded workflow with complete data
|
||||
const frontendFilters = {issue_type: '', column: '', labels: []};
|
||||
const frontendActions: WorkflowActionsState = {column: '', add_labels: [], remove_labels: [], issueState: ''};
|
||||
const frontendFilters = {issue_type: '', target_column: '', labels: []};
|
||||
const frontendActions: WorkflowActionsState = {column: '', add_labels: [], remove_labels: [], issue_state: ''};
|
||||
|
||||
if (store.selectedWorkflow.filters && Array.isArray(store.selectedWorkflow.filters)) {
|
||||
for (const filter of store.selectedWorkflow.filters) {
|
||||
if (filter.type === 'issue_type') {
|
||||
frontendFilters.issue_type = filter.value;
|
||||
} else if (filter.type === 'column') {
|
||||
frontendFilters.column = filter.value;
|
||||
} else if (filter.type === 'target_column') {
|
||||
frontendFilters.target_column = filter.value;
|
||||
} else if (filter.type === 'labels') {
|
||||
frontendFilters.labels.push(filter.value);
|
||||
}
|
||||
@ -286,9 +284,9 @@ export function createWorkflowStore(props: {projectLink: string, eventID: string
|
||||
frontendActions.remove_labels.push(action.value);
|
||||
} else if (action.type === 'close') {
|
||||
if (action.value === 'reopen' || action.value === 'false') {
|
||||
frontendActions.issueState = 'reopen';
|
||||
frontendActions.issue_state = 'reopen';
|
||||
} else if (action.value === 'true' || action.value === 'close') {
|
||||
frontendActions.issueState = 'close';
|
||||
frontendActions.issue_state = 'close';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user