From 555d64d024a69f249b42ff354e06226b5ff7c746 Mon Sep 17 00:00:00 2001
From: wxiaoguang <wxiaoguang@gmail.com>
Date: Mon, 24 Feb 2025 16:40:46 +0800
Subject: [PATCH] Always show the "rerun" button for action jobs (#33692)

And improve the mock code.
---
 routers/web/devtest/mock_actions.go      | 38 ++++++++++++++++++++++--
 routers/web/web.go                       |  1 +
 templates/devtest/repo-action-view.tmpl  |  9 ++++--
 web_src/js/components/RepoActionView.vue | 12 ++------
 4 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/routers/web/devtest/mock_actions.go b/routers/web/devtest/mock_actions.go
index e6539bb31f..3ce75dfad2 100644
--- a/routers/web/devtest/mock_actions.go
+++ b/routers/web/devtest/mock_actions.go
@@ -52,13 +52,22 @@ func generateMockStepsLog(logCur actions.LogCursor) (stepsLog []*actions.ViewSte
 	return stepsLog
 }
 
-func MockActionsRunsJobs(ctx *context.Context) {
-	req := web.GetForm(ctx).(*actions.ViewRequest)
+func MockActionsView(ctx *context.Context) {
+	ctx.Data["RunID"] = ctx.PathParam("run")
+	ctx.Data["JobID"] = ctx.PathParam("job")
+	ctx.HTML(http.StatusOK, "devtest/repo-action-view")
+}
 
+func MockActionsRunsJobs(ctx *context.Context) {
+	runID := ctx.PathParamInt64("run")
+
+	req := web.GetForm(ctx).(*actions.ViewRequest)
 	resp := &actions.ViewResponse{}
 	resp.State.Run.TitleHTML = `mock run title <a href="/">link</a>`
 	resp.State.Run.Status = actions_model.StatusRunning.String()
-	resp.State.Run.CanCancel = true
+	resp.State.Run.CanCancel = runID == 10
+	resp.State.Run.CanApprove = runID == 20
+	resp.State.Run.CanRerun = runID == 30
 	resp.State.Run.CanDeleteArtifact = true
 	resp.State.Run.WorkflowID = "workflow-id"
 	resp.State.Run.WorkflowLink = "./workflow-link"
@@ -85,6 +94,29 @@ func MockActionsRunsJobs(ctx *context.Context) {
 		Size:   1024 * 1024,
 		Status: "completed",
 	})
+
+	resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
+		ID:       runID * 10,
+		Name:     "job 100",
+		Status:   actions_model.StatusRunning.String(),
+		CanRerun: true,
+		Duration: "1h",
+	})
+	resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
+		ID:       runID*10 + 1,
+		Name:     "job 101",
+		Status:   actions_model.StatusWaiting.String(),
+		CanRerun: false,
+		Duration: "2h",
+	})
+	resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
+		ID:       runID*10 + 2,
+		Name:     "job 102",
+		Status:   actions_model.StatusFailure.String(),
+		CanRerun: false,
+		Duration: "3h",
+	})
+
 	resp.State.CurrentJob.Steps = append(resp.State.CurrentJob.Steps, &actions.ViewJobStep{
 		Summary:  "step 0 (mock slow)",
 		Duration: time.Hour.String(),
diff --git a/routers/web/web.go b/routers/web/web.go
index a5175e8830..01dc8cf697 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1634,6 +1634,7 @@ func registerRoutes(m *web.Router) {
 			m.Any("", devtest.List)
 			m.Any("/fetch-action-test", devtest.FetchActionTest)
 			m.Any("/{sub}", devtest.Tmpl)
+			m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView)
 			m.Post("/actions-mock/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
 		})
 	}
diff --git a/templates/devtest/repo-action-view.tmpl b/templates/devtest/repo-action-view.tmpl
index 9c6bdf13da..677eccc062 100644
--- a/templates/devtest/repo-action-view.tmpl
+++ b/templates/devtest/repo-action-view.tmpl
@@ -1,8 +1,13 @@
 {{template "base/head" .}}
 <div class="page-content">
+	<div class="tw-flex tw-justify-center tw-items-center tw-gap-5">
+		<a href="/devtest/repo-action-view/10/100">Run:CanCancel</a>
+		<a href="/devtest/repo-action-view/20/200">Run:CanApprove</a>
+		<a href="/devtest/repo-action-view/30/300">Run:CanRerun</a>
+	</div>
 	{{template "repo/actions/view_component" (dict
-		"RunIndex" 1
-		"JobIndex" 2
+		"RunIndex" (or .RunID 10)
+		"JobIndex" (or .JobID 100)
 		"ActionsURL" (print AppSubUrl "/devtest/actions-mock")
 	)}}
 </div>
diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue
index 03c8464060..2ef528620d 100644
--- a/web_src/js/components/RepoActionView.vue
+++ b/web_src/js/components/RepoActionView.vue
@@ -105,7 +105,6 @@ export default defineComponent({
       intervalID: null as IntervalId | null,
       currentJobStepsStates: [] as Array<Record<string, any>>,
       artifacts: [] as Array<Record<string, any>>,
-      onHoverRerunIndex: -1,
       menuVisible: false,
       isFullScreen: false,
       timeVisible: {
@@ -120,7 +119,7 @@ export default defineComponent({
         link: '',
         title: '',
         titleHTML: '',
-        status: 'unknown' as RunStatus,
+        status: '' as RunStatus, // do not show the status before initialized, otherwise it would show an incorrect "error" icon
         canCancel: false,
         canApprove: false,
         canRerun: false,
@@ -492,13 +491,13 @@ export default defineComponent({
       <div class="action-view-left">
         <div class="job-group-section">
           <div class="job-brief-list">
-            <a class="job-brief-item" :href="run.link+'/jobs/'+index" :class="parseInt(jobIndex) === index ? 'selected' : ''" v-for="(job, index) in run.jobs" :key="job.id" @mouseenter="onHoverRerunIndex = job.id" @mouseleave="onHoverRerunIndex = -1">
+            <a class="job-brief-item" :href="run.link+'/jobs/'+index" :class="parseInt(jobIndex) === index ? 'selected' : ''" v-for="(job, index) in run.jobs" :key="job.id">
               <div class="job-brief-item-left">
                 <ActionRunStatus :locale-status="locale.status[job.status]" :status="job.status"/>
                 <span class="job-brief-name tw-mx-2 gt-ellipsis">{{ job.name }}</span>
               </div>
               <span class="job-brief-item-right">
-                <SvgIcon name="octicon-sync" role="button" :data-tooltip-content="locale.rerun" class="job-brief-rerun tw-mx-2 link-action" :data-url="`${run.link}/jobs/${index}/rerun`" v-if="job.canRerun && onHoverRerunIndex === job.id"/>
+                <SvgIcon name="octicon-sync" role="button" :data-tooltip-content="locale.rerun" class="job-brief-rerun tw-mx-2 link-action" :data-url="`${run.link}/jobs/${index}/rerun`" v-if="job.canRerun"/>
                 <span class="step-summary-duration">{{ job.duration }}</span>
               </span>
             </a>
@@ -721,11 +720,6 @@ export default defineComponent({
 
 .job-brief-item .job-brief-rerun {
   cursor: pointer;
-  transition: transform 0.2s;
-}
-
-.job-brief-item .job-brief-rerun:hover {
-  transform: scale(130%);
 }
 
 .job-brief-item .job-brief-item-left {