From 1a045fa62eea705f2946ed816f84387987715571 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 29 Dec 2025 22:31:39 -0800 Subject: [PATCH] Use camel case in typescript --- package.json | 1 + pnpm-lock.yaml | 38 +++++ routers/web/projects/workflows.go | 4 +- .../components/projects/ProjectWorkflow.vue | 140 +++++++++--------- .../js/components/projects/WorkflowStore.ts | 109 ++++++++------ 5 files changed, 173 insertions(+), 119 deletions(-) diff --git a/package.json b/package.json index 7954e15046..a541828eb9 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "add-asset-webpack-plugin": "3.1.1", "ansi_up": "6.0.6", "asciinema-player": "3.13.5", + "camelcase-keys": "10.0.1", "chart.js": "4.5.1", "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82d899b5fd..663d804d92 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,6 +74,9 @@ importers: asciinema-player: specifier: 3.13.5 version: 3.13.5 + camelcase-keys: + specifier: 10.0.1 + version: 10.0.1 chart.js: specifier: 4.5.1 version: 4.5.1 @@ -1917,6 +1920,14 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} + camelcase-keys@10.0.1: + resolution: {integrity: sha512-kIH5nQUKB8ORZrwjk40GUgnhzuzxwKb6n5L+anOVmVSrjgix1pfNqVNl0tEcOP4AaFYdke3NNpNiGDSD112lcA==} + engines: {node: '>=20'} + + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + caniuse-lite@1.0.30001760: resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} @@ -3194,6 +3205,10 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + map-obj@5.0.2: + resolution: {integrity: sha512-K6K2NgKnTXimT3779/4KxSvobxOtMmx1LBZ3NwRxT/MDIR3Br/fQ4Q+WCX5QxjyUR8zg5+RV9Tbf2c5pAWTD2A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + markdown-it@14.1.0: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true @@ -3709,6 +3724,10 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-lru@7.3.0: + resolution: {integrity: sha512-k9lSsjl36EJdK7I06v7APZCbyGT2vMTsYSRX1Q2nbYmnkBqgUhRkAuzH08Ciotteu/PLJmIF2+tti7o3C/ts2g==} + engines: {node: '>=18'} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -4159,6 +4178,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + typescript-eslint@8.50.0: resolution: {integrity: sha512-Q1/6yNUmCpH94fbgMUMg2/BSAr/6U7GBk61kZTv1/asghQOWOjTlp9K8mixS5NcJmm2creY+UFfGeW/+OcA64A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5868,6 +5891,15 @@ snapshots: camelcase-css@2.0.1: {} + camelcase-keys@10.0.1: + dependencies: + camelcase: 8.0.0 + map-obj: 5.0.2 + quick-lru: 7.3.0 + type-fest: 4.41.0 + + camelcase@8.0.0: {} + caniuse-lite@1.0.30001760: {} chai@6.2.1: {} @@ -7221,6 +7253,8 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + map-obj@5.0.2: {} + markdown-it@14.1.0: dependencies: argparse: 2.0.1 @@ -7818,6 +7852,8 @@ snapshots: queue-microtask@1.2.3: {} + quick-lru@7.3.0: {} + randombytes@2.1.0: dependencies: safe-buffer: '@nolyfill/safe-buffer@1.0.44' @@ -8331,6 +8367,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@4.41.0: {} + typescript-eslint@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: '@typescript-eslint/eslint-plugin': 8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) diff --git a/routers/web/projects/workflows.go b/routers/web/projects/workflows.go index 7e133df9d4..a1a732d60a 100644 --- a/routers/web/projects/workflows.go +++ b/routers/web/projects/workflows.go @@ -176,7 +176,7 @@ type WorkflowConfig struct { Actions []project_model.WorkflowAction `json:"actions"` Summary string `json:"summary"` // Human readable filter description Enabled bool `json:"enabled"` - IsConfigured bool `json:"isConfigured"` // Whether this workflow is configured/saved + IsConfigured bool `json:"is_configured"` // Whether this workflow is configured/saved } func WorkflowsEvents(ctx *context.Context, project *project_model.Project) { @@ -447,7 +447,7 @@ func WorkflowsPost(ctx *context.Context) { workflowSummary := project_service.GetWorkflowSummary(ctx, wf) ctx.JSON(http.StatusOK, map[string]any{ "success": true, - "workflows": WorkflowConfig{ + "workflow": WorkflowConfig{ ID: wf.ID, EventID: strconv.FormatInt(wf.ID, 10), DisplayName: string(ctx.Tr(wf.WorkflowEvent.LangKey())), diff --git a/web_src/js/components/projects/ProjectWorkflow.vue b/web_src/js/components/projects/ProjectWorkflow.vue index 71ac7913ab..20089531a4 100644 --- a/web_src/js/components/projects/ProjectWorkflow.vue +++ b/web_src/js/components/projects/ProjectWorkflow.vue @@ -84,22 +84,22 @@ const setEditMode = (enabled: boolean) => { const showCancelButton = computed(() => { if (!store.selectedWorkflow) return false; if (store.selectedWorkflow.id > 0) return true; - const eventId = store.selectedWorkflow.event_id ?? ''; + const eventId = store.selectedWorkflow.eventId ?? ''; return typeof eventId === 'string' && eventId.startsWith('clone-'); }); const isTemporaryWorkflow = (workflow?: WorkflowEvent | null) => { if (!workflow) return false; if (workflow.id > 0) return false; - const eventId = typeof workflow.event_id === 'string' ? workflow.event_id : ''; + const eventId = typeof workflow.eventId === 'string' ? workflow.eventId : ''; return eventId.startsWith('clone-') || eventId.startsWith('new-'); }; const removeTemporaryWorkflow = (workflow?: WorkflowEvent | null) => { if (!workflow || !isTemporaryWorkflow(workflow)) return; - const eventId = workflow.event_id; - const tempIndex = store.workflowEvents.findIndex((w: WorkflowEvent) => w.event_id === eventId); + const eventId = workflow.eventId; + const tempIndex = store.workflowEvents.findIndex((w: WorkflowEvent) => w.eventId === eventId); if (tempIndex >= 0) { store.workflowEvents.splice(tempIndex, 1); } @@ -125,20 +125,20 @@ const toggleEditMode = () => { store.selectedItem = previousSelection.value.selectedItem; store.selectedWorkflow = previousSelection.value.selectedWorkflow; if (previousSelection.value.selectedWorkflow) { - store.loadWorkflowData(previousSelection.value.selectedWorkflow.event_id); + store.loadWorkflowData(previousSelection.value.selectedWorkflow.eventId); } previousSelection.value = null; } else if (hadTemporarySelection) { // If we removed a temporary item but have no previous selection, fall back to first workflow const fallback = store.workflowEvents.find((w: WorkflowEvent) => { if (!canceledWorkflow) return false; - const baseType = canceledWorkflow.workflow_event; - return baseType && (w.workflow_event === baseType || w.event_id === baseType); + const baseType = canceledWorkflow.workflowEvent; + return baseType && (w.workflowEvent === baseType || w.eventId === baseType); }) || store.workflowEvents[0]; if (fallback) { - store.selectedItem = fallback.event_id; + store.selectedItem = fallback.eventId; store.selectedWorkflow = fallback; - store.loadWorkflowData(fallback.event_id); + store.loadWorkflowData(fallback.eventId); } else { store.selectedItem = null; store.selectedWorkflow = null; @@ -174,7 +174,7 @@ const deleteWorkflow = async () => { // If deleting a temporary workflow (new or cloned, unsaved), just remove from list if (currentSelection.id === 0) { const tempIndex = store.workflowEvents.findIndex((w: WorkflowEvent) => - w.event_id === currentSelection.event_id, + w.eventId === currentSelection.eventId, ); if (tempIndex >= 0) { store.workflowEvents.splice(tempIndex, 1); @@ -188,7 +188,7 @@ const deleteWorkflow = async () => { // Find workflows for the same base event type const sameEventWorkflows = store.workflowEvents.filter((w: WorkflowEvent) => - (w.workflow_event === currentSelection.workflow_event) + (w.workflowEvent === currentSelection.workflowEvent) ); let workflowToSelect: WorkflowListItem | null = null; @@ -231,18 +231,18 @@ const cloneWorkflow = (sourceWorkflow?: WorkflowEvent | null) => { if (!sourceWorkflow) return; // Generate a unique temporary ID for the cloned workflow - const tempId = `${sourceWorkflow.workflow_event}`; + const tempId = `${sourceWorkflow.workflowEvent}`; // Extract base name without any parenthetical descriptions - const baseName = (sourceWorkflow.display_name || sourceWorkflow.workflow_event || sourceWorkflow.event_id) + const baseName = (sourceWorkflow.displayName || sourceWorkflow.workflowEvent || sourceWorkflow.eventId) .replace(/\s*\([^)]*\)\s*/g, ''); // Create a new workflow object based on the source const clonedWorkflow = { id: 0, // New workflow - event_id: tempId, - display_name: `${baseName} (Copy)`, - workflow_event: sourceWorkflow.workflow_event, + eventId: tempId, + displayName: `${baseName} (Copy)`, + workflowEvent: sourceWorkflow.workflowEvent, capabilities: sourceWorkflow.capabilities, filters: JSON.parse(JSON.stringify(sourceWorkflow.filters || [])), // Deep clone actions: JSON.parse(JSON.stringify(sourceWorkflow.actions || [])), // Deep clone @@ -251,7 +251,7 @@ const cloneWorkflow = (sourceWorkflow?: WorkflowEvent | null) => { }; // Insert cloned workflow right after the source workflow (keep same type together) - const sourceIndex = store.workflowEvents.findIndex((w: WorkflowEvent) => w.event_id === sourceWorkflow.event_id); + const sourceIndex = store.workflowEvents.findIndex((w: WorkflowEvent) => w.eventId === sourceWorkflow.eventId); if (sourceIndex >= 0) { store.workflowEvents.splice(sourceIndex + 1, 0, clonedWorkflow); } else { @@ -285,22 +285,22 @@ const selectWorkflowEvent = async (event: WorkflowEvent) => { if (store.loading) return; // If already selected, do nothing (keep selection active) - if (store.selectedItem === event.event_id) { + if (store.selectedItem === event.eventId) { return; } try { - store.selectedItem = event.event_id; + store.selectedItem = event.eventId; store.selectedWorkflow = event; // Wait for DOM update before proceeding await nextTick(); - await store.loadWorkflowData(event.event_id); + await store.loadWorkflowData(event.eventId); // Update URL without page reload - const newUrl = `${props.projectLink}/workflows/${event.event_id}`; - window.history.pushState({eventId: event.event_id}, '', newUrl); + const newUrl = `${props.projectLink}/workflows/${event.eventId}`; + window.history.pushState({eventId: event.eventId}, '', newUrl); } catch (error) { console.error('Error selecting workflow event:', error); // On error, try to select the first available workflow instead of clearing @@ -322,7 +322,7 @@ const saveWorkflow = async () => { const isWorkflowConfigured = (event: WorkflowEvent) => { // Check if the event_id is a number (saved workflow ID) or if it has id > 0 - return !Number.isNaN(parseInt(event.event_id)) || (event.id !== undefined && event.id > 0); + return !Number.isNaN(parseInt(event.eventId)) || (event.id !== undefined && event.id > 0); }; // Get flat list of all workflows - use cached data to prevent frequent recomputation @@ -336,7 +336,7 @@ const workflowList = computed(() => { return workflows.map((workflow: WorkflowEvent) => ({ ...workflow, isConfigured: isWorkflowConfigured(workflow), - display_name: workflow.display_name || workflow.workflow_event || workflow.event_id, + displayName: workflow.displayName || workflow.workflowEvent || workflow.eventId, })); }); @@ -363,28 +363,28 @@ const selectWorkflowItem = async (item: WorkflowListItem) => { } else { // This is an unconfigured event - check if we already have a workflow object for it const existingWorkflow = store.workflowEvents.find((w: WorkflowEvent) => - w.id === 0 && w.workflow_event === item.workflow_event, + w.id === 0 && w.workflowEvent === item.workflowEvent, ); const workflowToSelect = existingWorkflow || item; await selectWorkflowEvent(workflowToSelect); // Update URL for workflow - const newUrl = `${props.projectLink}/workflows/${item.workflow_event}`; - window.history.pushState({eventId: item.workflow_event}, '', newUrl); + const newUrl = `${props.projectLink}/workflows/${item.workflowEvent}`; + window.history.pushState({eventId: item.workflowEvent}, '', newUrl); } }; const hasAvailableFilters = computed(() => { - return (store.selectedWorkflow?.capabilities?.available_filters?.length ?? 0) > 0; + return (store.selectedWorkflow?.capabilities?.availableFilters?.length ?? 0) > 0; }); const hasFilter = (filterType: any) => { - return store.selectedWorkflow?.capabilities?.available_filters?.includes(filterType); + return store.selectedWorkflow?.capabilities?.availableFilters?.includes(filterType); }; const hasAction = (actionType: any) => { - return store.selectedWorkflow?.capabilities?.available_actions?.includes(actionType); + return store.selectedWorkflow?.capabilities?.availableActions?.includes(actionType); }; // Toggle label selection for add_labels, remove_labels, or filter_labels @@ -392,8 +392,10 @@ const toggleLabel = (type: string, labelId: any) => { let labels; if (type === 'filter_labels') { labels = store.workflowFilters.labels; - } else { - labels = (store.workflowActions as any)[type]; + } else if (type === 'add_labels') { + labels = (store.workflowActions as any)['addLabels']; + } else if (type === 'remove_labels') { + labels = (store.workflowActions as any)['removeLabels']; } const index = labels.indexOf(labelId); if (index > -1) { @@ -426,20 +428,20 @@ const isItemSelected = (item: WorkflowListItem) => { if (item.isConfigured || item.id === 0) { // For configured workflows or temporary workflows (new), match by event_id - return store.selectedItem === item.event_id; + return store.selectedItem === item.eventId; } // For unconfigured events, match by workflow_event - return store.selectedItem === item.workflow_event; + return store.selectedItem === item.workflowEvent; }; // Get display name for workflow with numbering for same types const getWorkflowDisplayName = (item: WorkflowListItem, _index: number) => { const list = workflowList.value; - const displayName = item.display_name || item.workflow_event || item.event_id || ''; + const displayName = item.displayName || item.workflowEvent || item.eventId || ''; // Find all workflows of the same type const sameTypeWorkflows = list.filter((w: WorkflowListItem) => - w.workflow_event === item.workflow_event && + w.workflowEvent === item.workflowEvent && (w.isConfigured || w.id === 0) // Only count configured workflows ); @@ -449,7 +451,7 @@ const getWorkflowDisplayName = (item: WorkflowListItem, _index: number) => { } // Find the index of this workflow among same-type workflows - const sameTypeIndex = sameTypeWorkflows.findIndex((w: WorkflowListItem) => w.event_id === item.event_id); + const sameTypeIndex = sameTypeWorkflows.findIndex((w: WorkflowListItem) => w.eventId === item.eventId); // Extract base name without filter summary (remove anything in parentheses) const baseName = displayName.replace(/\s*\([^)]*\)\s*$/g, ''); @@ -461,7 +463,7 @@ const getWorkflowDisplayName = (item: WorkflowListItem, _index: number) => { const getCurrentDraftKey = () => { if (!store.selectedWorkflow) return null; - return store.selectedWorkflow.event_id || store.selectedWorkflow.workflow_event; + return store.selectedWorkflow.eventId || store.selectedWorkflow.workflowEvent; }; const persistDraftState = () => { @@ -533,7 +535,7 @@ onMounted(async () => { // Auto-select logic if (props.eventID) { // If eventID is provided in URL, try to find and select it - const selectedEvent = store.workflowEvents.find((e: WorkflowEvent) => e.event_id === props.eventID); + const selectedEvent = store.workflowEvents.find((e: WorkflowEvent) => e.eventId === props.eventID); if (selectedEvent) { // Found existing configured workflow store.selectedItem = props.eventID; @@ -543,7 +545,7 @@ onMounted(async () => { // Check if eventID matches a base event type (unconfigured workflow) const items = workflowList.value; const matchingUnconfigured = items.find((item: WorkflowListItem) => - !item.isConfigured && (item.workflow_event === props.eventID || item.event_id === props.eventID), + !item.isConfigured && (item.workflowEvent === props.eventID || item.eventId === props.eventID), ); if (matchingUnconfigured) { // Select the placeholder workflow for this base event type @@ -587,14 +589,14 @@ onMounted(async () => { const popstateHandler = (e: PopStateEvent) => { if (e.state?.eventId) { // Handle browser back/forward navigation - const event = store.workflowEvents.find((ev: WorkflowEvent) => ev.event_id === e.state.eventId); + const event = store.workflowEvents.find((ev: WorkflowEvent) => ev.eventId === e.state.eventId); if (event) { void selectWorkflowEvent(event); } else { // Check if it's a base event type const items = workflowList.value; const matchingUnconfigured = items.find((item: WorkflowListItem) => - !item.isConfigured && (item.workflow_event === e.state.eventId || item.event_id === e.state.eventId), + !item.isConfigured && (item.workflowEvent === e.state.eventId || item.eventId === e.state.eventId), ); if (matchingUnconfigured) { void selectWorkflowEvent(matchingUnconfigured); @@ -635,7 +637,7 @@ onUnmounted(() => {
{

- {{ store.selectedWorkflow.display_name }} + {{ store.selectedWorkflow.displayName }} {
- {{ locale.runWhen }}{{ store.selectedWorkflow.display_name }} + {{ locale.runWhen }}{{ store.selectedWorkflow.displayName }}

@@ -779,15 +781,15 @@ onUnmounted(() => {
- {{ store.workflowFilters.issue_type === 'issue' ? locale.issuesOnly : - store.workflowFilters.issue_type === 'pull_request' ? locale.pullRequestsOnly : + {{ store.workflowFilters.issueType === 'issue' ? locale.issuesOnly : + store.workflowFilters.issueType === 'pull_request' ? locale.pullRequestsOnly : locale.issuesAndPullRequests }}
@@ -796,7 +798,7 @@ onUnmounted(() => {
- {{ store.projectColumns.find(c => String(c.id) === store.workflowFilters.source_column)?.title || locale.anyColumn }} + {{ store.projectColumns.find(c => String(c.id) === store.workflowFilters.sourceColumn)?.title || locale.anyColumn }}
@@ -813,7 +815,7 @@ onUnmounted(() => {
- {{ store.projectColumns.find(c => String(c.id) === store.workflowFilters.target_column)?.title || locale.anyColumn }} + {{ store.projectColumns.find(c => String(c.id) === store.workflowFilters.targetColumn)?.title || locale.anyColumn }}
@@ -894,13 +896,13 @@ onUnmounted(() => {