mirror of
https://github.com/go-gitea/gitea.git
synced 2026-02-24 23:27:08 +01:00
fix
This commit is contained in:
parent
58a368021f
commit
a18eba0026
@ -4,14 +4,17 @@
|
||||
package projects
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
project_model "code.gitea.io/gitea/models/project"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
)
|
||||
|
||||
@ -55,6 +58,14 @@ func convertFormToFilters(formFilters map[string]string) []project_model.Workflo
|
||||
return filters
|
||||
}
|
||||
|
||||
func convertFiltersToMap(filters []project_model.WorkflowFilter) map[string]string {
|
||||
filterMap := make(map[string]string)
|
||||
for _, filter := range filters {
|
||||
filterMap[string(filter.Type)] = filter.Value
|
||||
}
|
||||
return filterMap
|
||||
}
|
||||
|
||||
// convertFormToActions converts form actions to WorkflowAction objects
|
||||
func convertFormToActions(formActions map[string]any) []project_model.WorkflowAction {
|
||||
actions := make([]project_model.WorkflowAction, 0)
|
||||
@ -62,11 +73,14 @@ func convertFormToActions(formActions map[string]any) []project_model.WorkflowAc
|
||||
for key, value := range formActions {
|
||||
switch key {
|
||||
case "column":
|
||||
if strValue, ok := value.(string); ok && strValue != "" {
|
||||
actions = append(actions, project_model.WorkflowAction{
|
||||
ActionType: project_model.WorkflowActionTypeColumn,
|
||||
ActionValue: strValue,
|
||||
})
|
||||
if floatValue, ok := value.(float64); ok {
|
||||
floatValueInt := int64(floatValue)
|
||||
if floatValueInt > 0 {
|
||||
actions = append(actions, project_model.WorkflowAction{
|
||||
ActionType: project_model.WorkflowActionTypeColumn,
|
||||
ActionValue: strconv.FormatInt(floatValueInt, 10),
|
||||
})
|
||||
}
|
||||
}
|
||||
case "add_labels":
|
||||
if labels, ok := value.([]string); ok && len(labels) > 0 {
|
||||
@ -103,6 +117,14 @@ func convertFormToActions(formActions map[string]any) []project_model.WorkflowAc
|
||||
return actions
|
||||
}
|
||||
|
||||
func convertActionsToMap(actions []project_model.WorkflowAction) map[string]any {
|
||||
actionMap := make(map[string]any)
|
||||
for _, action := range actions {
|
||||
actionMap[string(action.ActionType)] = action.ActionValue
|
||||
}
|
||||
return actionMap
|
||||
}
|
||||
|
||||
func WorkflowsEvents(ctx *context.Context) {
|
||||
projectID := ctx.PathParamInt64("id")
|
||||
p, err := project_model.GetProjectByID(ctx, projectID)
|
||||
@ -134,8 +156,8 @@ func WorkflowsEvents(ctx *context.Context) {
|
||||
EventID string `json:"event_id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Capabilities project_model.WorkflowEventCapabilities `json:"capabilities"`
|
||||
Filters []project_model.WorkflowFilter `json:"filters"`
|
||||
Actions []project_model.WorkflowAction `json:"actions"`
|
||||
Filters map[string]string `json:"filters"`
|
||||
Actions map[string]any `json:"actions"`
|
||||
FilterSummary string `json:"filter_summary"` // Human readable filter description
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
@ -161,8 +183,8 @@ func WorkflowsEvents(ctx *context.Context) {
|
||||
EventID: strconv.FormatInt(wf.ID, 10),
|
||||
DisplayName: string(ctx.Tr(wf.WorkflowEvent.LangKey())) + filterSummary,
|
||||
Capabilities: capabilities[event],
|
||||
Filters: wf.WorkflowFilters,
|
||||
Actions: wf.WorkflowActions,
|
||||
Filters: convertFiltersToMap(wf.WorkflowFilters),
|
||||
Actions: convertActionsToMap(wf.WorkflowActions),
|
||||
FilterSummary: filterSummary,
|
||||
Enabled: wf.Enabled,
|
||||
})
|
||||
@ -174,8 +196,6 @@ func WorkflowsEvents(ctx *context.Context) {
|
||||
EventID: event.UUID(),
|
||||
DisplayName: string(ctx.Tr(event.LangKey())),
|
||||
Capabilities: capabilities[event],
|
||||
Filters: []project_model.WorkflowFilter{},
|
||||
Actions: []project_model.WorkflowAction{},
|
||||
FilterSummary: "",
|
||||
Enabled: true, // Default to enabled for new workflows
|
||||
})
|
||||
@ -354,9 +374,9 @@ func Workflows(ctx *context.Context) {
|
||||
}
|
||||
|
||||
type WorkflowsPostForm struct {
|
||||
EventID string `form:"event_id" binding:"Required"`
|
||||
Filters map[string]string `form:"filters"`
|
||||
Actions map[string]any `form:"actions"`
|
||||
EventID string `json:"event_id"`
|
||||
Filters map[string]string `json:"filters"`
|
||||
Actions map[string]any `json:"actions"`
|
||||
}
|
||||
|
||||
func WorkflowsPost(ctx *context.Context) {
|
||||
@ -379,7 +399,24 @@ func WorkflowsPost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
form := web.GetForm(ctx).(*WorkflowsPostForm)
|
||||
// Handle both form data and JSON data
|
||||
// Handle JSON data
|
||||
form := &WorkflowsPostForm{}
|
||||
content, err := io.ReadAll(ctx.Req.Body)
|
||||
if err != nil {
|
||||
ctx.ServerError("ReadRequestBody", err)
|
||||
return
|
||||
}
|
||||
defer ctx.Req.Body.Close()
|
||||
log.Trace("get " + string(content))
|
||||
if err := json.Unmarshal(content, &form); err != nil {
|
||||
ctx.ServerError("DecodeWorkflowsPostForm", err)
|
||||
return
|
||||
}
|
||||
if form.EventID == "" {
|
||||
ctx.ServerError("InvalidEventID", errors.New("EventID is required"))
|
||||
return
|
||||
}
|
||||
|
||||
// Convert form data to filters and actions
|
||||
filters := convertFormToFilters(form.Filters)
|
||||
|
||||
@ -1041,10 +1041,10 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Group("/{id}/workflows", func() {
|
||||
m.Get("", projects.Workflows)
|
||||
m.Get("/{workflow_id}", projects.Workflows)
|
||||
m.Post("/{workflow_id}", web.Bind(projects.WorkflowsPostForm{}), projects.WorkflowsPost)
|
||||
m.Post("/{workflow_id}", projects.WorkflowsPost)
|
||||
m.Post("/{workflow_id}/status", projects.WorkflowsStatus)
|
||||
m.Post("/{workflow_id}/delete", projects.WorkflowsDelete)
|
||||
})
|
||||
}, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead, true))
|
||||
m.Group("", func() { //nolint:dupl // duplicates lines 1421-1441
|
||||
m.Get("/new", org.RenderNewProject)
|
||||
m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost)
|
||||
@ -1435,7 +1435,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Group("/{id}/workflows", func() {
|
||||
m.Get("", projects.Workflows)
|
||||
m.Get("/{workflow_id}", projects.Workflows)
|
||||
m.Post("/{workflow_id}", web.Bind(projects.WorkflowsPostForm{}), projects.WorkflowsPost)
|
||||
m.Post("/{workflow_id}", projects.WorkflowsPost)
|
||||
m.Post("/{workflow_id}/status", projects.WorkflowsStatus)
|
||||
m.Post("/{workflow_id}/delete", projects.WorkflowsDelete)
|
||||
})
|
||||
|
||||
@ -48,8 +48,8 @@ const toggleEditMode = () => {
|
||||
// If there was a previous selection, return to it
|
||||
if (store.selectedWorkflow && store.selectedWorkflow.id === 0) {
|
||||
// Remove temporary cloned workflow from list
|
||||
const tempIndex = store.workflowEvents.findIndex(w =>
|
||||
w.event_id === store.selectedWorkflow.event_id
|
||||
const tempIndex = store.workflowEvents.findIndex((w) =>
|
||||
w.event_id === store.selectedWorkflow.event_id,
|
||||
);
|
||||
if (tempIndex >= 0) {
|
||||
store.workflowEvents.splice(tempIndex, 1);
|
||||
@ -69,7 +69,7 @@ const toggleEditMode = () => {
|
||||
// Entering edit mode - store current selection
|
||||
previousSelection.value = {
|
||||
selectedItem: store.selectedItem,
|
||||
selectedWorkflow: store.selectedWorkflow ? {...store.selectedWorkflow} : null
|
||||
selectedWorkflow: store.selectedWorkflow ? {...store.selectedWorkflow} : null,
|
||||
};
|
||||
setEditMode(true);
|
||||
}
|
||||
@ -84,7 +84,7 @@ const toggleWorkflowStatus = async () => {
|
||||
};
|
||||
|
||||
const deleteWorkflow = async () => {
|
||||
if (!store.selectedWorkflow || !confirm('Are you sure you want to delete this workflow?')) {
|
||||
if (!store.selectedWorkflow || !window.confirm('Are you sure you want to delete this workflow?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -96,8 +96,8 @@ const deleteWorkflow = async () => {
|
||||
|
||||
// If deleting a temporary workflow (clone/new), just remove from list
|
||||
if (store.selectedWorkflow.id === 0) {
|
||||
const tempIndex = store.workflowEvents.findIndex(w =>
|
||||
w.event_id === store.selectedWorkflow.event_id
|
||||
const tempIndex = store.workflowEvents.findIndex((w) =>
|
||||
w.event_id === store.selectedWorkflow.event_id,
|
||||
);
|
||||
if (tempIndex >= 0) {
|
||||
store.workflowEvents.splice(tempIndex, 1);
|
||||
@ -110,9 +110,9 @@ const deleteWorkflow = async () => {
|
||||
}
|
||||
|
||||
// Find workflows for the same base event type
|
||||
const sameEventWorkflows = store.workflowEvents.filter(w =>
|
||||
const sameEventWorkflows = store.workflowEvents.filter((w) =>
|
||||
w.base_event_type === currentBaseEventType ||
|
||||
w.workflow_event === currentBaseEventType
|
||||
w.workflow_event === currentBaseEventType,
|
||||
);
|
||||
|
||||
if (sameEventWorkflows.length === 0) {
|
||||
@ -226,7 +226,7 @@ const createNewWorkflow = (baseEventType, capabilities, displayName) => {
|
||||
if (!isInEditMode.value) {
|
||||
previousSelection.value = {
|
||||
selectedItem: store.selectedItem,
|
||||
selectedWorkflow: store.selectedWorkflow ? {...store.selectedWorkflow} : null
|
||||
selectedWorkflow: store.selectedWorkflow ? {...store.selectedWorkflow} : null,
|
||||
};
|
||||
}
|
||||
|
||||
@ -255,7 +255,7 @@ const cloneWorkflow = (sourceWorkflow) => {
|
||||
// Store current selection before cloning
|
||||
previousSelection.value = {
|
||||
selectedItem: store.selectedItem,
|
||||
selectedWorkflow: store.selectedWorkflow ? {...store.selectedWorkflow} : null
|
||||
selectedWorkflow: store.selectedWorkflow ? {...store.selectedWorkflow} : null,
|
||||
};
|
||||
|
||||
const tempId = `clone-${sourceWorkflow.base_event_type || sourceWorkflow.workflow_event}-${Date.now()}`;
|
||||
@ -276,7 +276,7 @@ const cloneWorkflow = (sourceWorkflow) => {
|
||||
};
|
||||
|
||||
// Find the position of source workflow and insert cloned workflow after it
|
||||
const sourceIndex = store.workflowEvents.findIndex(w => w.event_id === sourceWorkflow.event_id);
|
||||
const sourceIndex = store.workflowEvents.findIndex((w) => w.event_id === sourceWorkflow.event_id);
|
||||
if (sourceIndex >= 0) {
|
||||
store.workflowEvents.splice(sourceIndex + 1, 0, clonedWorkflow);
|
||||
} else {
|
||||
@ -318,9 +318,9 @@ const selectWorkflowItem = async (item) => {
|
||||
await selectWorkflowEvent(item);
|
||||
} else {
|
||||
// This is an unconfigured event - check if we already have a workflow object for it
|
||||
const existingWorkflow = store.workflowEvents.find(w =>
|
||||
const existingWorkflow = store.workflowEvents.find((w) =>
|
||||
w.id === 0 &&
|
||||
(w.base_event_type === item.base_event_type || w.workflow_event === item.base_event_type)
|
||||
(w.base_event_type === item.base_event_type || w.workflow_event === item.base_event_type),
|
||||
);
|
||||
|
||||
if (existingWorkflow) {
|
||||
@ -368,10 +368,9 @@ const isItemSelected = (item) => {
|
||||
if (item.isConfigured || item.id === 0) {
|
||||
// For configured workflows or temporary workflows (clones/new), match by event_id
|
||||
return store.selectedItem === item.event_id;
|
||||
} else {
|
||||
// For unconfigured events, match by base_event_type
|
||||
return store.selectedItem === item.base_event_type;
|
||||
}
|
||||
// For unconfigured events, match by base_event_type
|
||||
return store.selectedItem === item.base_event_type;
|
||||
};
|
||||
|
||||
const _getActionsSummary = (workflow) => {
|
||||
@ -446,7 +445,7 @@ onMounted(async () => {
|
||||
// Check if eventID matches a base event type (unconfigured workflow)
|
||||
const items = workflowList.value;
|
||||
const matchingUnconfigured = items.find((item) =>
|
||||
!item.isConfigured && (item.base_event_type === props.eventID || item.event_id === props.eventID)
|
||||
!item.isConfigured && (item.base_event_type === props.eventID || item.event_id === props.eventID),
|
||||
);
|
||||
if (matchingUnconfigured) {
|
||||
// Create new workflow for this base event type
|
||||
@ -496,7 +495,7 @@ const popstateHandler = (e) => {
|
||||
// Check if it's a base event type
|
||||
const items = workflowList.value;
|
||||
const matchingUnconfigured = items.find((item) =>
|
||||
!item.isConfigured && (item.base_event_type === e.state.eventId || item.event_id === e.state.eventId)
|
||||
!item.isConfigured && (item.base_event_type === e.state.eventId || item.event_id === e.state.eventId),
|
||||
);
|
||||
if (matchingUnconfigured) {
|
||||
createNewWorkflow(matchingUnconfigured.base_event_type, matchingUnconfigured.capabilities, matchingUnconfigured.display_name);
|
||||
@ -578,9 +577,11 @@ onUnmounted(() => {
|
||||
<h2>
|
||||
<i class="settings icon"/>
|
||||
{{ store.selectedWorkflow.display_name }}
|
||||
<span v-if="store.selectedWorkflow.id > 0 && !isInEditMode"
|
||||
class="workflow-status"
|
||||
:class="store.selectedWorkflow.enabled ? 'status-enabled' : 'status-disabled'">
|
||||
<span
|
||||
v-if="store.selectedWorkflow.id > 0 && !isInEditMode"
|
||||
class="workflow-status"
|
||||
:class="store.selectedWorkflow.enabled ? 'status-enabled' : 'status-disabled'"
|
||||
>
|
||||
{{ store.selectedWorkflow.enabled ? 'Enabled' : 'Disabled' }}
|
||||
</span>
|
||||
</h2>
|
||||
@ -625,114 +626,115 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor-content">
|
||||
<div class="form" :class="{ 'readonly': !isInEditMode }">
|
||||
<div class="field">
|
||||
<label>When</label>
|
||||
<div class="segment">
|
||||
<div class="description">
|
||||
This workflow will run when: <strong>{{ store.selectedWorkflow.display_name }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filters Section -->
|
||||
<div class="field" v-if="hasAvailableFilters">
|
||||
<label>Filters</label>
|
||||
<div class="segment">
|
||||
<div class="field" v-if="hasFilter('issue_type')">
|
||||
<label>Apply to</label>
|
||||
<select
|
||||
v-if="isInEditMode"
|
||||
class="form-select"
|
||||
v-model="store.workflowFilters.issue_type"
|
||||
>
|
||||
<option value="">Issues And Pull Requests</option>
|
||||
<option value="issue">Issues</option>
|
||||
<option value="pull_request">Pull requests</option>
|
||||
</select>
|
||||
<div v-else class="readonly-value">
|
||||
{{ store.workflowFilters.issue_type === 'issue' ? 'Issues' :
|
||||
store.workflowFilters.issue_type === 'pull_request' ? 'Pull requests' :
|
||||
'Issues And Pull Requests' }}
|
||||
<!--<form class="ui form form-fetch-action" :action="props.projectLink+'/workflows/'+store.selectedWorkflow.id" method="post">-->
|
||||
<div class="editor-content">
|
||||
<div class="form" :class="{ 'readonly': !isInEditMode }">
|
||||
<div class="field">
|
||||
<label>When</label>
|
||||
<div class="segment">
|
||||
<div class="description">
|
||||
This workflow will run when: <strong>{{ store.selectedWorkflow.display_name }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions Section -->
|
||||
<div class="field">
|
||||
<label>Actions</label>
|
||||
<div class="segment">
|
||||
<div class="field" v-if="hasAction('column')">
|
||||
<label>Move to column</label>
|
||||
<select
|
||||
v-if="isInEditMode"
|
||||
class="form-select"
|
||||
v-model="store.workflowActions.column"
|
||||
>
|
||||
<option value="">Select column...</option>
|
||||
<option v-for="column in store.projectColumns" :key="column.id" :value="column.id">
|
||||
{{ column.title }}
|
||||
</option>
|
||||
</select>
|
||||
<div v-else class="readonly-value">
|
||||
{{ store.projectColumns.find(c => c.id === store.workflowActions.column)?.title || 'None' }}
|
||||
<!-- Filters Section -->
|
||||
<div class="field" v-if="hasAvailableFilters">
|
||||
<label>Filters</label>
|
||||
<div class="segment">
|
||||
<div class="field" v-if="hasFilter('issue_type')">
|
||||
<label>Apply to</label>
|
||||
<select
|
||||
v-if="isInEditMode"
|
||||
class="form-select"
|
||||
v-model="store.workflowFilters.issue_type"
|
||||
>
|
||||
<option value="">Issues And Pull Requests</option>
|
||||
<option value="issue">Issues</option>
|
||||
<option value="pull_request">Pull requests</option>
|
||||
</select>
|
||||
<div v-else class="readonly-value">
|
||||
{{ store.workflowFilters.issue_type === 'issue' ? 'Issues' :
|
||||
store.workflowFilters.issue_type === 'pull_request' ? 'Pull requests' :
|
||||
'Issues And Pull Requests' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field" v-if="hasAction('label')">
|
||||
<label>Add labels</label>
|
||||
<select
|
||||
v-if="isInEditMode"
|
||||
class="form-select"
|
||||
v-model="store.workflowActions.labels"
|
||||
multiple
|
||||
>
|
||||
<option value="">Select labels...</option>
|
||||
<option v-for="label in store.projectLabels" :key="label.id" :value="label.id">
|
||||
{{ label.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div v-else class="readonly-value">
|
||||
{{ store.workflowActions.labels?.map(id =>
|
||||
store.projectLabels.find(l => l.id === id)?.name).join(', ') || 'None' }}
|
||||
<!-- Actions Section -->
|
||||
<div class="field">
|
||||
<label>Actions</label>
|
||||
<div class="segment">
|
||||
<div class="field" v-if="hasAction('column')">
|
||||
<label>Move to column</label>
|
||||
<select
|
||||
v-if="isInEditMode"
|
||||
class="form-select"
|
||||
v-model="store.workflowActions.column"
|
||||
>
|
||||
<option value="">Select column...</option>
|
||||
<option v-for="column in store.projectColumns" :key="column.id" :value="column.id">
|
||||
{{ column.title }}
|
||||
</option>
|
||||
</select>
|
||||
<div v-else class="readonly-value">
|
||||
{{ store.projectColumns.find(c => c.id === store.workflowActions.column)?.title || 'None' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field" v-if="hasAction('close')">
|
||||
<div v-if="isInEditMode" class="form-check">
|
||||
<input type="checkbox" v-model="store.workflowActions.closeIssue" id="close-issue">
|
||||
<label for="close-issue">Close issue</label>
|
||||
<div class="field" v-if="hasAction('label')">
|
||||
<label>Add labels</label>
|
||||
<select
|
||||
v-if="isInEditMode"
|
||||
class="form-select"
|
||||
v-model="store.workflowActions.add_labels"
|
||||
multiple
|
||||
>
|
||||
<option value="">Select labels...</option>
|
||||
<option v-for="label in store.projectLabels" :key="label.id" :value="label.id">
|
||||
{{ label.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div v-else class="readonly-value">
|
||||
{{ store.workflowActions.add_labels?.map(id =>
|
||||
store.projectLabels.find(l => l.id === id)?.name).join(', ') || 'None' }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="readonly-value">
|
||||
<label>Close issue</label>
|
||||
<div>{{ store.workflowActions.closeIssue ? 'Yes' : 'No' }}</div>
|
||||
|
||||
<div class="field" v-if="hasAction('close')">
|
||||
<div v-if="isInEditMode" class="form-check">
|
||||
<input type="checkbox" v-model="store.workflowActions.closeIssue" id="close-issue">
|
||||
<label for="close-issue">Close issue</label>
|
||||
</div>
|
||||
<div v-else class="readonly-value">
|
||||
<label>Close issue</label>
|
||||
<div>{{ store.workflowActions.closeIssue ? 'Yes' : 'No' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fixed bottom actions (only show in edit mode) -->
|
||||
<div v-if="isInEditMode" class="editor-actions">
|
||||
<button class="btn btn-primary" @click="saveWorkflow" :disabled="store.saving">
|
||||
<i class="save icon"/>
|
||||
Save Workflow
|
||||
</button>
|
||||
<button
|
||||
v-if="store.selectedWorkflow && store.selectedWorkflow.id > 0"
|
||||
class="btn btn-danger"
|
||||
@click="deleteWorkflow"
|
||||
>
|
||||
<i class="trash icon"/>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<!-- Fixed bottom actions (only show in edit mode) -->
|
||||
<div v-if="isInEditMode" class="editor-actions">
|
||||
<button class="btn btn-primary" @click="saveWorkflow" :disabled="store.saving">
|
||||
<i class="save icon"/>
|
||||
Save Workflow
|
||||
</button>
|
||||
<button
|
||||
v-if="store.selectedWorkflow && store.selectedWorkflow.id > 0"
|
||||
class="btn btn-danger"
|
||||
@click="deleteWorkflow"
|
||||
>
|
||||
<i class="trash icon"/>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<!--</form>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
|
||||
|
||||
workflowActions: {
|
||||
column: '', // column ID to move to
|
||||
labels: [], // selected label IDs
|
||||
add_labels: [], // selected label IDs
|
||||
closeIssue: false,
|
||||
},
|
||||
|
||||
@ -67,7 +67,7 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
|
||||
if (action.action_type === 'column') {
|
||||
frontendActions.column = action.action_value;
|
||||
} else if (action.action_type === 'add_labels') {
|
||||
frontendActions.labels.push(action.action_value);
|
||||
frontendActions.add_labels.push(action.action_value);
|
||||
} else if (action.action_type === 'close') {
|
||||
frontendActions.closeIssue = action.action_value === 'true';
|
||||
}
|
||||
@ -108,49 +108,23 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
|
||||
// For new workflows, use the base event type
|
||||
const eventId = store.selectedWorkflow.base_event_type || store.selectedWorkflow.event_id;
|
||||
|
||||
// Convert frontend data format to backend form format
|
||||
const formData = new FormData();
|
||||
formData.append('event_id', eventId);
|
||||
// Convert frontend data format to backend JSON format
|
||||
const postData = {
|
||||
event_id: eventId,
|
||||
filters: store.workflowFilters,
|
||||
actions: store.workflowActions,
|
||||
};
|
||||
|
||||
// Add filters as form fields
|
||||
for (const [key, value] of Object.entries(store.workflowFilters)) {
|
||||
if (value !== '') {
|
||||
formData.append(`filters[${key}]`, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Add actions as form fields
|
||||
for (const [key, value] of Object.entries(store.workflowActions)) {
|
||||
if (key === 'labels' && Array.isArray(value)) {
|
||||
// Handle label array
|
||||
for (const labelId of value) {
|
||||
if (labelId !== '') {
|
||||
formData.append(`actions[labels][]`, labelId);
|
||||
}
|
||||
}
|
||||
} else if (key === 'closeIssue') {
|
||||
// Handle boolean
|
||||
formData.append(`actions[${key}]`, value.toString());
|
||||
} else if (value !== '') {
|
||||
// Handle string fields
|
||||
formData.append(`actions[${key}]`, value);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Saving workflow with FormData');
|
||||
console.log('URL:', `${props.projectLink}/workflows/${eventId}`);
|
||||
// Log form data entries
|
||||
for (const [key, value] of formData.entries()) {
|
||||
console.log(`${key}: ${value}`);
|
||||
}
|
||||
// Send workflow data
|
||||
console.info('Sending workflow data:', postData);
|
||||
|
||||
const response = await POST(`${props.projectLink}/workflows/${eventId}`, {
|
||||
data: formData,
|
||||
data: postData,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
console.log('Response status:', response.status);
|
||||
console.log('Response headers:', response.headers);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error('Response error:', errorText);
|
||||
@ -163,8 +137,8 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
|
||||
if (result.success && result.workflow) {
|
||||
// Always reload the events list to get the updated structure
|
||||
// This ensures we have both the base event and the new filtered event
|
||||
const wasNewWorkflow = store.selectedWorkflow.id === 0 ||
|
||||
store.selectedWorkflow.event_id.startsWith('new-') ||
|
||||
const wasNewWorkflow = store.selectedWorkflow.id === 0 ||
|
||||
store.selectedWorkflow.event_id.startsWith('new-') ||
|
||||
store.selectedWorkflow.event_id.startsWith('clone-');
|
||||
|
||||
// Reload events from server to get the correct event structure
|
||||
@ -222,7 +196,6 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
|
||||
if (existingIndex >= 0) {
|
||||
store.workflowEvents[existingIndex].enabled = store.selectedWorkflow.enabled;
|
||||
}
|
||||
console.log(`Workflow status updated to: ${store.selectedWorkflow.enabled ? 'enabled' : 'disabled'}`);
|
||||
} else {
|
||||
// Revert the status change on failure
|
||||
store.selectedWorkflow.enabled = !store.selectedWorkflow.enabled;
|
||||
@ -260,7 +233,6 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
|
||||
if (existingIndex >= 0) {
|
||||
store.workflowEvents.splice(existingIndex, 1);
|
||||
}
|
||||
console.log('Workflow deleted successfully');
|
||||
} else {
|
||||
alert('Failed to delete workflow');
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user