improvements

pull/30205/head
Lunny Xiao 2025-09-03 16:24:42 -07:00
parent dd635586b1
commit 20b4ce5446
No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
6 changed files with 304 additions and 74 deletions

View File

@ -16,27 +16,25 @@ import (
type WorkflowEvent string
const (
WorkflowEventItemOpened WorkflowEvent = "item_opened"
WorkflowEventItemAddedToProject WorkflowEvent = "item_added_to_project"
WorkflowEventItemReopened WorkflowEvent = "item_reopened"
WorkflowEventItemClosed WorkflowEvent = "item_closed"
WorkflowEventItemColumnChanged WorkflowEvent = "item_column_changed"
WorkflowEventCodeChangesRequested WorkflowEvent = "code_changes_requested"
WorkflowEventCodeReviewApproved WorkflowEvent = "code_review_approved"
WorkflowEventPullRequestMerged WorkflowEvent = "pull_request_merged"
WorkflowEventAutoArchiveItems WorkflowEvent = "auto_archive_items"
WorkflowEventAutoAddToProject WorkflowEvent = "auto_add_to_project"
WorkflowEventAutoCloseIssue WorkflowEvent = "auto_close_issue"
)
var workflowEvents = []WorkflowEvent{
WorkflowEventItemOpened,
WorkflowEventItemAddedToProject,
WorkflowEventItemReopened,
WorkflowEventItemClosed,
WorkflowEventItemColumnChanged,
WorkflowEventCodeChangesRequested,
WorkflowEventCodeReviewApproved,
WorkflowEventPullRequestMerged,
WorkflowEventAutoArchiveItems,
WorkflowEventAutoAddToProject,
WorkflowEventAutoCloseIssue,
}
func GetWorkflowEvents() []WorkflowEvent {
@ -45,24 +43,22 @@ func GetWorkflowEvents() []WorkflowEvent {
func (we WorkflowEvent) LangKey() string {
switch we {
case WorkflowEventItemOpened:
return "projects.workflows.event.item_opened"
case WorkflowEventItemAddedToProject:
return "projects.workflows.event.item_added_to_project"
case WorkflowEventItemReopened:
return "projects.workflows.event.item_reopened"
case WorkflowEventItemClosed:
return "projects.workflows.event.item_closed"
case WorkflowEventItemColumnChanged:
return "projects.workflows.event.item_column_changed"
case WorkflowEventCodeChangesRequested:
return "projects.workflows.event.code_changes_requested"
case WorkflowEventCodeReviewApproved:
return "projects.workflows.event.code_review_approved"
case WorkflowEventPullRequestMerged:
return "projects.workflows.event.pull_request_merged"
case WorkflowEventAutoArchiveItems:
return "projects.workflows.event.auto_archive_items"
case WorkflowEventAutoAddToProject:
return "projects.workflows.event.auto_add_to_project"
case WorkflowEventAutoCloseIssue:
return "projects.workflows.event.auto_close_issue"
default:
return string(we)
}
@ -70,24 +66,22 @@ func (we WorkflowEvent) LangKey() string {
func (we WorkflowEvent) UUID() string {
switch we {
case WorkflowEventItemOpened:
return "item_opened"
case WorkflowEventItemAddedToProject:
return "item_added_to_project"
case WorkflowEventItemReopened:
return "item_reopened"
case WorkflowEventItemClosed:
return "item_closed"
case WorkflowEventItemColumnChanged:
return "item_column_changed"
case WorkflowEventCodeChangesRequested:
return "code_changes_requested"
case WorkflowEventCodeReviewApproved:
return "code_review_approved"
case WorkflowEventPullRequestMerged:
return "pull_request_merged"
case WorkflowEventAutoArchiveItems:
return "auto_archive_items"
case WorkflowEventAutoAddToProject:
return "auto_add_to_project"
case WorkflowEventAutoCloseIssue:
return "auto_close_issue"
default:
return string(we)
}
@ -96,20 +90,21 @@ func (we WorkflowEvent) UUID() string {
type WorkflowFilterType string
const (
WorkflowFilterTypeScope WorkflowFilterType = "scope" // issue, pull_request, etc.
WorkflowFilterTypeIssueType WorkflowFilterType = "issue_type" // issue, pull_request, etc.
)
type WorkflowFilter struct {
Type WorkflowFilterType
Value string // e.g., "issue", "pull_request", etc.
Value string // e.g., "issue", "pull_request", etc. depends on the filter type definition
}
type WorkflowActionType string
const (
WorkflowActionTypeColumn WorkflowActionType = "column" // add the item to the project's column
WorkflowActionTypeLabel WorkflowActionType = "label" // choose one or more labels
WorkflowActionTypeClose WorkflowActionType = "close" // close the issue
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
)
type WorkflowAction struct {
@ -119,48 +114,44 @@ type WorkflowAction struct {
// WorkflowEventCapabilities defines what filters and actions are available for each event
type WorkflowEventCapabilities struct {
AvailableFilters []string `json:"available_filters"`
AvailableFilters []WorkflowFilterType `json:"available_filters"`
AvailableActions []WorkflowActionType `json:"available_actions"`
}
// GetWorkflowEventCapabilities returns the capabilities for each workflow event
func GetWorkflowEventCapabilities() map[WorkflowEvent]WorkflowEventCapabilities {
return map[WorkflowEvent]WorkflowEventCapabilities{
WorkflowEventItemOpened: {
AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeIssueType}, // issue, pull_request
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeAddLabels},
},
WorkflowEventItemAddedToProject: {
AvailableFilters: []string{"scope"}, // issue, pull_request
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeLabel},
AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeIssueType}, // issue, pull_request
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels},
},
WorkflowEventItemReopened: {
AvailableFilters: []string{"scope"},
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeLabel},
AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeIssueType},
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels},
},
WorkflowEventItemClosed: {
AvailableFilters: []string{"scope"},
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeLabel},
AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeIssueType},
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels},
},
WorkflowEventItemColumnChanged: {
AvailableFilters: []WorkflowFilterType{WorkflowFilterTypeIssueType},
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels, WorkflowActionTypeClose},
},
WorkflowEventCodeChangesRequested: {
AvailableFilters: []string{}, // only applies to pull requests
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeLabel},
AvailableFilters: []WorkflowFilterType{}, // only applies to pull requests
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels},
},
WorkflowEventCodeReviewApproved: {
AvailableFilters: []string{}, // only applies to pull requests
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeLabel},
AvailableFilters: []WorkflowFilterType{}, // only applies to pull requests
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels},
},
WorkflowEventPullRequestMerged: {
AvailableFilters: []string{}, // only applies to pull requests
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeLabel, WorkflowActionTypeClose},
},
WorkflowEventAutoArchiveItems: {
AvailableFilters: []string{"scope"},
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn},
},
WorkflowEventAutoAddToProject: {
AvailableFilters: []string{"scope"},
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeLabel},
},
WorkflowEventAutoCloseIssue: {
AvailableFilters: []string{}, // only applies to issues
AvailableActions: []WorkflowActionType{WorkflowActionTypeClose, WorkflowActionTypeLabel},
AvailableFilters: []WorkflowFilterType{}, // only applies to pull requests
AvailableActions: []WorkflowActionType{WorkflowActionTypeColumn, WorkflowActionTypeAddLabels, WorkflowActionTypeRemoveLabels},
},
}
}

View File

@ -3904,15 +3904,14 @@ type-3.display_name = Organization Project
enter_fullscreen = Fullscreen
workflows = Workflows
exit_fullscreen = Exit Fullscreen
workflows.event.item_opened = Item opened
workflows.event.item_added_to_project = Item added to project
workflows.event.item_reopened = Item reopened
workflows.event.item_closed = Item closed
workflows.event.item_column_changed = Item column changed
workflows.event.code_changes_requested = Code changes requested
workflows.event.code_review_approved = Code review approved
workflows.event.pull_request_merged = Pull request merged
workflows.event.auto_archive_items = Auto archive items
workflows.event.auto_add_to_project = Auto add to project
workflows.event.auto_close_issue = Auto close issue
[git.filemode]
changed_filemode = %[1]s → %[2]s

View File

@ -68,12 +68,23 @@ func convertFormToActions(formActions map[string]any) []project_model.WorkflowAc
ActionValue: strValue,
})
}
case "labels":
case "add_labels":
if labels, ok := value.([]string); ok && len(labels) > 0 {
for _, label := range labels {
if label != "" {
actions = append(actions, project_model.WorkflowAction{
ActionType: project_model.WorkflowActionTypeLabel,
ActionType: project_model.WorkflowActionTypeAddLabels,
ActionValue: label,
})
}
}
}
case "remove_labels":
if labels, ok := value.([]string); ok && len(labels) > 0 {
for _, label := range labels {
if label != "" {
actions = append(actions, project_model.WorkflowAction{
ActionType: project_model.WorkflowActionTypeRemoveLabels,
ActionValue: label,
})
}

View File

@ -89,7 +89,7 @@ func (m *workflowNotifier) IssueChangeStatus(ctx context.Context, doer *user_mod
func fireIssueWorkflow(ctx context.Context, workflow *project_model.Workflow, issue *issues_model.Issue) {
for _, filter := range workflow.WorkflowFilters {
switch filter.Type {
case project_model.WorkflowFilterTypeScope:
case project_model.WorkflowFilterTypeIssueType:
values := strings.Split(filter.Value, ",")
if !(slices.Contains(values, "issue") && !issue.IsPull) || (slices.Contains(values, "pull") && issue.IsPull) {
return

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import {onMounted, useTemplateRef, computed} from 'vue';
import {onMounted, useTemplateRef, computed, ref} from 'vue';
import {createWorkflowStore} from './WorkflowStore.ts';
import {svg} from '../../svg.ts';
@ -12,6 +12,49 @@ const props = defineProps({
const store = createWorkflowStore(props);
const editMode = ref(false);
const toggleEditMode = () => {
editMode.value = !editMode.value;
};
const toggleWorkflowStatus = async () => {
if (store.selectedWorkflow) {
// Toggle the enabled status
store.selectedWorkflow.enabled = !store.selectedWorkflow.enabled;
await store.saveWorkflowStatus();
}
};
const deleteWorkflow = async () => {
if (!store.selectedWorkflow || !confirm('Are you sure you want to delete this workflow?')) {
return;
}
await store.deleteWorkflow();
// Refresh workflow list
store.workflowEvents = await store.loadEvents();
// Find workflows for the same base event type
const sameEventWorkflows = store.workflowEvents.filter(w =>
w.base_event_type === store.selectedWorkflow.base_event_type ||
w.workflow_event === store.selectedWorkflow.base_event_type
);
if (sameEventWorkflows.length === 0) {
// No workflows left for this event type, create an empty one
const baseEventType = store.selectedWorkflow.base_event_type;
const displayName = store.selectedWorkflow.display_name.split(' (')[0]; // Remove filter suffix
createNewWorkflow(baseEventType, store.selectedWorkflow.capabilities, displayName);
} else {
// Select the first remaining workflow of the same type
selectWorkflowItem(sameEventWorkflows[0]);
}
editMode.value = false;
};
const selectWorkflowEvent = (event) => {
// Toggle selection - if already selected, deselect
if (store.selectedItem === event.event_id) {
@ -60,11 +103,13 @@ const createNewWorkflow = (baseEventType, capabilities, displayName) => {
actions: [],
filter_summary: '',
base_event_type: baseEventType,
enabled: true,
};
store.selectedWorkflow = newWorkflow;
store.selectedItem = tempId;
store.resetWorkflowData();
editMode.value = true; // Auto-enter edit mode for new workflows
};
const cloneWorkflow = (sourceWorkflow) => {
@ -78,6 +123,7 @@ const cloneWorkflow = (sourceWorkflow) => {
actions: Array.from(sourceWorkflow.actions || []),
filter_summary: '',
base_event_type: sourceWorkflow.base_event_type || sourceWorkflow.workflow_event,
enabled: true,
};
store.selectedWorkflow = clonedWorkflow;
@ -85,9 +131,11 @@ const cloneWorkflow = (sourceWorkflow) => {
// Load the source workflow's data into the form
store.loadWorkflowData(sourceWorkflow.event_id);
editMode.value = true; // Auto-enter edit mode for cloned workflows
};
const selectWorkflowItem = (item) => {
editMode.value = false; // Reset edit mode when switching workflows
if (item.isConfigured) {
// This is a configured workflow, select it
selectWorkflowEvent(item);
@ -121,11 +169,16 @@ const _getActionsSummary = (workflow) => {
if (column) {
actions.push(`Move to "${column.title}"`);
}
} else if (action.action_type === 'label') {
} else if (action.action_type === 'add_labels') {
const label = store.projectLabels.find((l) => l.id === action.action_value);
if (label) {
actions.push(`Add label "${label.name}"`);
}
} else if (action.action_type === 'remove_labels') {
const label = store.projectLabels.find((l) => l.id === action.action_value);
if (label) {
actions.push(`Remove label "${label.name}"`);
}
} else if (action.action_type === 'close') {
actions.push('Close issue');
}
@ -233,12 +286,41 @@ onMounted(async () => {
<h2>
<i class="settings icon"/>
{{ store.selectedWorkflow.display_name }}
<span v-if="store.selectedWorkflow.id > 0 && !editMode"
class="workflow-status"
:class="store.selectedWorkflow.enabled ? 'status-enabled' : 'status-disabled'">
{{ store.selectedWorkflow.enabled ? 'Enabled' : 'Disabled' }}
</span>
</h2>
<p>Configure automated actions for this workflow</p>
<p v-if="editMode">Configure automated actions for this workflow</p>
<p v-else>View workflow configuration</p>
</div>
<div class="editor-actions-header">
<!-- Edit/Cancel Button -->
<button
v-if="store.selectedWorkflow && store.selectedWorkflow.id > 0"
class="ui button"
:class="editMode ? 'basic' : 'primary'"
@click="toggleEditMode"
>
<i :class="editMode ? 'times icon' : 'edit icon'"/>
{{ editMode ? 'Cancel' : 'Edit' }}
</button>
<!-- Enable/Disable Button (only for configured workflows) -->
<button
v-if="store.selectedWorkflow && store.selectedWorkflow.id > 0 && !editMode"
class="ui button"
:class="store.selectedWorkflow.enabled ? 'red basic' : 'green'"
@click="toggleWorkflowStatus"
:title="store.selectedWorkflow.enabled ? 'Disable workflow' : 'Enable workflow'"
>
<i :class="store.selectedWorkflow.enabled ? 'pause icon' : 'play icon'"/>
{{ store.selectedWorkflow.enabled ? 'Disable' : 'Enable' }}
</button>
<!-- Clone Button (only for configured workflows) -->
<button
v-if="store.selectedWorkflow && store.selectedWorkflow.id > 0 && !editMode"
class="ui basic button"
@click="cloneWorkflow(store.selectedWorkflow)"
title="Clone this workflow"
@ -250,7 +332,7 @@ onMounted(async () => {
</div>
<div class="editor-content">
<div class="ui form">
<div class="ui form" :class="{ 'readonly': !editMode }">
<div class="field">
<label>When</label>
<div class="ui segment">
@ -264,13 +346,22 @@ onMounted(async () => {
<div class="field" v-if="hasAvailableFilters">
<label>Filters</label>
<div class="ui segment">
<div class="field" v-if="hasFilter('scope')">
<div class="field" v-if="hasFilter('issue_type')">
<label>Apply to</label>
<select class="ui dropdown" v-model="store.workflowFilters.scope">
<select
v-if="editMode"
class="ui dropdown"
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>
@ -281,41 +372,68 @@ onMounted(async () => {
<div class="ui segment">
<div class="field" v-if="hasAction('column')">
<label>Move to column</label>
<select class="ui dropdown" v-model="store.workflowActions.column">
<select
v-if="editMode"
class="ui dropdown"
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 class="field" v-if="hasAction('label')">
<label>Add labels</label>
<select class="ui multiple dropdown" v-model="store.workflowActions.labels">
<select
v-if="editMode"
class="ui multiple dropdown"
v-model="store.workflowActions.labels"
>
<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' }}
</div>
</div>
<div class="field" v-if="hasAction('close')">
<div class="ui checkbox">
<div v-if="editMode" class="ui checkbox">
<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>
<!-- Fixed bottom actions -->
<div class="editor-actions">
<!-- Fixed bottom actions (only show in edit mode) -->
<div v-if="editMode" class="editor-actions">
<button class="ui primary button" @click="saveWorkflow" :class="{ loading: store.saving }">
<i class="save icon"/>
Save Workflow
</button>
<button
v-if="store.selectedWorkflow && store.selectedWorkflow.id > 0"
class="ui red button"
@click="deleteWorkflow"
>
<i class="trash icon"/>
Delete
</button>
</div>
</div>
</div>
@ -492,6 +610,9 @@ onMounted(async () => {
.editor-actions-header {
flex-shrink: 0;
display: flex;
gap: 0.5rem;
align-items: center;
}
.editor-content {
@ -576,4 +697,51 @@ onMounted(async () => {
width: 100%;
}
}
/* Workflow status styles */
.workflow-status {
display: inline-block;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 500;
margin-left: 0.5rem;
}
.workflow-status.status-enabled {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.workflow-status.status-disabled {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
/* Readonly form styles */
.ui.form.readonly {
pointer-events: none;
}
.readonly-value {
background: #f6f8fa;
padding: 0.5rem;
border: 1px solid #e1e4e8;
border-radius: 4px;
color: #24292e;
font-weight: 500;
}
.readonly-value label {
font-weight: 600;
margin-bottom: 0.25rem;
display: block;
}
.readonly-value div {
color: #586069;
font-weight: normal;
}
</style>

View File

@ -13,7 +13,7 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
selectedEventType: null, // For workflow creation
workflowFilters: {
scope: '', // 'issue', 'pull_request', or ''
issue_type: '', // 'issue', 'pull_request', or ''
},
workflowActions: {
@ -48,22 +48,22 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
if (workflow && workflow.filters && workflow.actions) {
// Load existing configuration from the workflow data
// Convert backend filter format to frontend format
const frontendFilters = {scope: ''};
const frontendFilters = {issue_type: ''};
if (workflow.filters && Array.isArray(workflow.filters)) {
for (const filter of workflow.filters) {
if (filter.type === 'scope') {
frontendFilters.scope = filter.value;
if (filter.type === 'issue_type') {
frontendFilters.issue_type = filter.value;
}
}
}
// Convert backend action format to frontend format
const frontendActions = {column: '', labels: [], closeIssue: false};
const frontendActions = {column: '', add_labels: [], closeIssue: false};
if (workflow.actions && Array.isArray(workflow.actions)) {
for (const action of workflow.actions) {
if (action.action_type === 'column') {
frontendActions.column = action.action_value;
} else if (action.action_type === 'label') {
} else if (action.action_type === 'add_labels') {
frontendActions.labels.push(action.action_value);
} else if (action.action_type === 'close') {
frontendActions.closeIssue = action.action_value === 'true';
@ -90,8 +90,8 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
},
resetWorkflowData() {
store.workflowFilters = {scope: ''};
store.workflowActions = {column: '', labels: [], closeIssue: false};
store.workflowFilters = {issue_type: ''};
store.workflowActions = {column: '', add_labels: [], closeIssue: false};
},
async saveWorkflow() {
@ -189,6 +189,67 @@ export function createWorkflowStore(props: { projectLink: string, eventID: strin
}
},
async saveWorkflowStatus() {
if (!store.selectedWorkflow || store.selectedWorkflow.id === 0) return;
try {
const formData = new FormData();
formData.append('enabled', store.selectedWorkflow.enabled.toString());
const response = await POST(`${props.projectLink}/workflows/${store.selectedWorkflow.event_id}/status`, {
data: formData,
});
if (!response.ok) {
const errorText = await response.text();
console.error('Failed to update workflow status:', errorText);
alert(`Failed to update workflow status: ${response.status} ${response.statusText}`);
return;
}
const result = await response.json();
if (result.success) {
// Update workflow in the list
const existingIndex = store.workflowEvents.findIndex((e) => e.event_id === store.selectedWorkflow.event_id);
if (existingIndex >= 0) {
store.workflowEvents[existingIndex].enabled = store.selectedWorkflow.enabled;
}
}
} catch (error) {
console.error('Error updating workflow status:', error);
alert(`Error updating workflow status: ${error.message}`);
}
},
async deleteWorkflow() {
if (!store.selectedWorkflow || store.selectedWorkflow.id === 0) return;
try {
const response = await POST(`${props.projectLink}/workflows/${store.selectedWorkflow.event_id}/delete`, {
data: new FormData(),
});
if (!response.ok) {
const errorText = await response.text();
console.error('Failed to delete workflow:', errorText);
alert(`Failed to delete workflow: ${response.status} ${response.statusText}`);
return;
}
const result = await response.json();
if (result.success) {
// Remove workflow from the list
const existingIndex = store.workflowEvents.findIndex((e) => e.event_id === store.selectedWorkflow.event_id);
if (existingIndex >= 0) {
store.workflowEvents.splice(existingIndex, 1);
}
}
} catch (error) {
console.error('Error deleting workflow:', error);
alert(`Error deleting workflow: ${error.message}`);
}
},
});
return store;
}