diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index e5742157d882..80ccecbce162 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -80,6 +80,7 @@ milestones = Milestones
 ok = OK
 cancel = Cancel
 rerun = Re-run
+rerun_all = Re-run all jobs
 save = Save
 add = Add
 add_all = Add All
diff --git a/templates/repo/actions/status.tmpl b/templates/repo/actions/status.tmpl
index ab2ee8482cf0..cdc747aa8b0b 100644
--- a/templates/repo/actions/status.tmpl
+++ b/templates/repo/actions/status.tmpl
@@ -1,5 +1,6 @@
 <!-- This template should be kept the same as web_src/js/components/ActionRunStatus.vue
 	Please also update the vue file above if this template is modified.
+	action status accepted: success, skipped, waiting, blocked, running, failure, cancelled, unknown
 -->
 {{- $size := 16 -}}
 {{- if .size -}}
@@ -11,7 +12,7 @@
 {{- $className = .className -}}
 {{- end -}}
 
-<span data-tooltip-content="{{.locale.Tr (printf "actions.status.%s" .status)}}">
+<span class="gt-df gt-ac" data-tooltip-content="{{.locale.Tr (printf "actions.status.%s" .status)}}">
 {{if eq .status "success"}}
 	{{svg "octicon-check-circle-fill" $size (printf "text green %s" $className)}}
 {{else if eq .status "skipped"}}
@@ -22,7 +23,7 @@
 	{{svg "octicon-blocked" $size (printf "text yellow %s" $className)}}
 {{else if eq .status "running"}}
 	{{svg "octicon-meter" $size (printf "text yellow job-status-rotate %s" $className)}}
-{{else}}
+{{else if or (eq .status "failure") or (eq .status "cancelled") or (eq .status "unknown")}}
 	{{svg "octicon-x-circle-fill" $size (printf "text red %s" $className)}}
 {{end}}
 </span>
diff --git a/templates/repo/actions/view.tmpl b/templates/repo/actions/view.tmpl
index 8d6559ee9800..3a3a069cbc8a 100644
--- a/templates/repo/actions/view.tmpl
+++ b/templates/repo/actions/view.tmpl
@@ -9,6 +9,7 @@
 		data-locale-approve="{{.locale.Tr "repo.diff.review.approve"}}"
 		data-locale-cancel="{{.locale.Tr "cancel"}}"
 		data-locale-rerun="{{.locale.Tr "rerun"}}"
+		data-locale-rerun-all="{{.locale.Tr "rerun_all"}}"
 		data-locale-status-unknown="{{.locale.Tr "actions.status.unknown"}}"
 		data-locale-status-waiting="{{.locale.Tr "actions.status.waiting"}}"
 		data-locale-status-running="{{.locale.Tr "actions.status.running"}}"
diff --git a/web_src/css/base.css b/web_src/css/base.css
index eb12ffef7a6c..4b9f1eef2249 100644
--- a/web_src/css/base.css
+++ b/web_src/css/base.css
@@ -71,6 +71,7 @@
   /* console colors */
   --color-console-fg: #ffffff;
   --color-console-bg: #171717;
+  --color-console-hover-bg: #ffffff16;
   /* named colors */
   --color-red: #db2828;
   --color-orange: #f2711c;
diff --git a/web_src/js/components/ActionRunStatus.vue b/web_src/js/components/ActionRunStatus.vue
index 0786cb60a9a4..bddf307a1b10 100644
--- a/web_src/js/components/ActionRunStatus.vue
+++ b/web_src/js/components/ActionRunStatus.vue
@@ -1,14 +1,15 @@
 <!-- This vue should be kept the same as templates/repo/actions/status.tmpl
     Please also update the template file above if this vue is modified.
+    action status accepted: success, skipped, waiting, blocked, running, failure, cancelled, unknown
 -->
 <template>
-  <span :data-tooltip-content="localeStatus" v-if="status">
+  <span class="gt-df gt-ac" :data-tooltip-content="localeStatus" v-if="status">
     <SvgIcon name="octicon-check-circle-fill" class="text green" :size="size" :class-name="className" v-if="status === 'success'"/>
     <SvgIcon name="octicon-skip" class="text grey" :size="size" :class-name="className" v-else-if="status === 'skipped'"/>
     <SvgIcon name="octicon-clock" class="text yellow" :size="size" :class-name="className" v-else-if="status === 'waiting'"/>
     <SvgIcon name="octicon-blocked" class="text yellow" :size="size" :class-name="className" v-else-if="status === 'blocked'"/>
     <SvgIcon name="octicon-meter" class="text yellow" :size="size" :class-name="'job-status-rotate ' + className" v-else-if="status === 'running'"/>
-    <SvgIcon name="octicon-x-circle-fill" class="text red" :size="size" v-else/>
+    <SvgIcon name="octicon-x-circle-fill" class="text red" :size="size" v-else-if="['failure', 'cancelled', 'unknown'].includes(status)" />
   </span>
 </template>
 
diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue
index 28adfbc6eca7..b2fd63dd18e9 100644
--- a/web_src/js/components/RepoActionView.vue
+++ b/web_src/js/components/RepoActionView.vue
@@ -1,28 +1,30 @@
 <template>
-  <div class="action-view-container">
+  <div class="ui container action-view-container">
     <div class="action-view-header">
       <div class="action-info-summary">
-        <ActionRunStatus :locale-status="locale.status[run.status]" :status="run.status" :size="20"/>
-        <div class="action-title">
-          {{ run.title }}
+        <div class="action-info-summary-title">
+          <ActionRunStatus :locale-status="locale.status[run.status]" :status="run.status" :size="20"/>
+          <h2 class="action-info-summary-title-text">
+            {{ run.title }}
+          </h2>
         </div>
         <button class="ui basic small compact button primary" @click="approveRun()" v-if="run.canApprove">
-          <SvgIcon class="gt-mr-2" name="octicon-play" :size="20"/> {{ locale.approve }}
+          {{ locale.approve }}
         </button>
         <button class="ui basic small compact button red" @click="cancelRun()" v-else-if="run.canCancel">
-          <SvgIcon class="gt-mr-2" name="octicon-x-circle-fill" :size="20"/> {{ locale.cancel }}
+          {{ locale.cancel }}
         </button>
         <button class="ui basic small compact button secondary" @click="rerun()" v-else-if="run.canRerun">
-          <SvgIcon class="gt-mr-2" name="octicon-sync" :size="20"/> {{ locale.rerun }}
+          {{ locale.rerun_all }}
         </button>
       </div>
       <div class="action-commit-summary">
         {{ run.commit.localeCommit }}
         <a :href="run.commit.link">{{ run.commit.shortSHA }}</a>
-        &nbsp;<span class="ui label" v-if="run.commit.shortSHA">
+        <span class="ui label" v-if="run.commit.shortSHA">
           <a :href="run.commit.branch.link">{{ run.commit.branch.name }}</a>
         </span>
-        &nbsp;{{ run.commit.localePushedBy }}
+        {{ run.commit.localePushedBy }}
         <a :href="run.commit.pusher.link">{{ run.commit.pusher.displayName }}</a>
       </div>
     </div>
@@ -30,15 +32,15 @@
       <div class="action-view-left">
         <div class="job-group-section">
           <div class="job-brief-list">
-            <div class="job-brief-item" v-for="(job, index) in run.jobs" :key="job.id">
+            <div class="job-brief-item" :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-link" :href="run.link+'/jobs/'+index">
                 <ActionRunStatus :locale-status="locale.status[job.status]" :status="job.status"/>
-                <span class="ui text gt-mx-3">{{ job.name }}</span>
+                <span class="job-brief-name gt-mx-3 gt-ellipsis">{{ job.name }}</span>
               </a>
-              <span class="step-summary-duration">{{ job.duration }}</span>
-              <button :data-tooltip-content="locale.rerun" class="job-brief-rerun" @click="rerunJob(index)" v-if="job.canRerun">
-                <SvgIcon name="octicon-sync" class="ui text black"/>
-              </button>
+              <span class="job-brief-info">
+                <span class="step-summary-duration">{{ job.duration }}</span>
+                <SvgIcon name="octicon-sync" role="button" :data-tooltip-content="locale.rerun" class="job-brief-rerun gt-mx-3" @click="rerunJob(index)" v-if="job.canRerun && onHoverRerunIndex === job.id"/>
+              </span>
             </div>
           </div>
         </div>
@@ -58,21 +60,24 @@
 
       <div class="action-view-right">
         <div class="job-info-header">
-          <div class="job-info-header-title">
+          <h3 class="job-info-header-title">
             {{ currentJob.title }}
-          </div>
-          <div class="job-info-header-detail">
+          </h3>
+          <p class="job-info-header-detail">
             {{ currentJob.detail }}
-          </div>
+          </p>
         </div>
         <div class="job-step-container">
           <div class="job-step-section" v-for="(jobStep, i) in currentJob.steps" :key="i">
-            <div class="job-step-summary" @click.stop="toggleStepLogs(i)">
-              <SvgIcon :name="currentJobStepsStates[i].expanded ? 'octicon-chevron-down': 'octicon-chevron-right'" class="gt-mr-3"/>
-
+            <div class="job-step-summary" @click.stop="toggleStepLogs(i)" :class="currentJobStepsStates[i].expanded ? 'selected' : ''">
+              <!-- If the job is done and the job step log is loaded for the first time, show the loading icon
+                currentJobStepsStates[i].cursor === null means the log is loaded for the first time
+              -->
+              <SvgIcon v-if="isDone(run.status) && currentJobStepsStates[i].expanded && currentJobStepsStates[i].cursor === null" name="octicon-sync" class="gt-mr-3 job-status-rotate"/>
+              <SvgIcon v-else :name="currentJobStepsStates[i].expanded ? 'octicon-chevron-down': 'octicon-chevron-right'" class="gt-mr-3"/>
               <ActionRunStatus :status="jobStep.status" class="gt-mr-3"/>
 
-              <span class="step-summary-msg">{{ jobStep.summary }}</span>
+              <span class="step-summary-msg gt-ellipsis">{{ jobStep.summary }}</span>
               <span class="step-summary-duration">{{ jobStep.duration }}</span>
             </div>
 
@@ -115,6 +120,7 @@ const sfc = {
       intervalID: null,
       currentJobStepsStates: [],
       artifacts: [],
+      onHoverRerunIndex: -1,
 
       // provided by backend
       run: {
@@ -295,6 +301,7 @@ const sfc = {
         // sync the currentJobStepsStates to store the job step states
         for (let i = 0; i < this.currentJob.steps.length; i++) {
           if (!this.currentJobStepsStates[i]) {
+            // initial states for job steps
             this.currentJobStepsStates[i] = {cursor: null, expanded: false};
           }
         }
@@ -325,6 +332,10 @@ const sfc = {
         body,
       });
     },
+
+    isDone(status) {
+      return ['success', 'skipped', 'failure', 'cancelled'].includes(status);
+    }
   },
 };
 
@@ -348,6 +359,7 @@ export function initRepositoryActionView() {
       cancel: el.getAttribute('data-locale-cancel'),
       rerun: el.getAttribute('data-locale-rerun'),
       artifactsTitle: el.getAttribute('data-locale-artifacts-title'),
+      rerun_all: el.getAttribute('data-locale-rerun-all'),
       status: {
         unknown: el.getAttribute('data-locale-status-unknown'),
         waiting: el.getAttribute('data-locale-status-waiting'),
@@ -417,24 +429,30 @@ export function ansiLogToHTML(line) {
 /* action view header */
 
 .action-view-header {
-  margin: 0 20px 20px 20px;
+  margin: 20px 0px;
 }
 
 .action-info-summary {
-  font-size: 150%;
-  height: 20px;
   display: flex;
   align-items: center;
   margin-top: 1rem;
+  justify-content: space-between;
 }
 
-.action-info-summary .action-title {
-  padding: 0 5px;
+.action-info-summary-title {
+  display: flex;
+}
+
+.action-info-summary-title-text {
+  font-size: 20px;
+  margin: 0 0 0 5px;
   flex: 1;
 }
 
 .action-commit-summary {
-  padding: 10px 10px;
+  display: flex;
+  gap: 5px;
+  margin: 10px 0px 10px 25px;
 }
 
 /* ================ */
@@ -444,7 +462,6 @@ export function ansiLogToHTML(line) {
   width: 30%;
   max-width: 400px;
   overflow-y: scroll;
-  margin-left: 10px;
 }
 
 .job-group-section .job-group-summary {
@@ -473,42 +490,64 @@ export function ansiLogToHTML(line) {
   padding-right: 3px;
 }
 
-.job-group-section .job-brief-list .job-brief-item {
+.job-brief-item {
   margin: 5px 0;
   padding: 10px;
   background: var(--color-info-bg);
   border-radius: 5px;
   text-decoration: none;
   display: flex;
-  justify-items: center;
   flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
 }
 
-.job-group-section .job-brief-list .job-brief-item .job-brief-rerun {
-  float: right;
-  border: none;
-  background-color: transparent;
-  outline: none;
+.job-brief-item:hover {
+  background-color: var(--color-secondary);
+}
+
+.job-brief-item.selected {
+  font-weight: var(--font-weight-bold);
+  background-color: var(--color-secondary-dark-1);
+}
+
+.job-brief-item:first-of-type {
+  margin-top: 0;
+}
+
+.job-brief-item .job-brief-rerun {
   cursor: pointer;
   transition: transform 0.2s;
 }
 
-.job-group-section .job-brief-list .job-brief-item .job-brief-rerun:hover {
+.job-brief-item .job-brief-rerun:hover {
   transform: scale(130%);
 }
 
-.job-group-section .job-brief-list .job-brief-item .job-brief-link {
-  flex-grow: 1;
+.job-brief-item .job-brief-link {
   display: flex;
+  width: 100%;
 }
 
-.job-group-section .job-brief-list .job-brief-item .job-brief-link span {
+.job-brief-item .job-brief-link span {
   display: flex;
   align-items: center;
 }
 
-.job-group-section .job-brief-list .job-brief-item:hover {
-  background-color: var(--color-secondary);
+.job-brief-item .job-brief-link .job-brief-name {
+  display: block;
+  width: 70%;
+  color: var(--color-text);
+}
+
+.job-brief-item .job-brief-link:hover {
+  text-decoration: none;
+}
+
+.job-brief-item .job-brief-info {
+  display: flex;
+  align-items: center;
+  width: 55px;
 }
 
 /* ================ */
@@ -517,21 +556,27 @@ export function ansiLogToHTML(line) {
 .action-view-right {
   flex: 1;
   background-color: var(--color-console-bg);
-  color: var(--color-console-fg);
+  color: var(--color-secondary-dark-2);
   max-height: 100%;
-  margin-right: 10px;
+  width: 70%;
   display: flex;
   flex-direction: column;
 }
 
-.job-info-header .job-info-header-title {
-  font-size: 150%;
+.job-info-header {
   padding: 10px;
+  border-bottom: 1px solid var(--color-grey);
+}
+
+.job-info-header .job-info-header-title {
+  color: var(--color-console-fg);
+  font-size: 16px;
+  margin: 0;
 }
 
 .job-info-header .job-info-header-detail {
-  padding: 0 10px 10px;
-  border-bottom: 1px solid var(--color-grey);
+  color: var(--color-secondary-dark-3);
+  font-size: 12px;
 }
 
 .job-step-container {
@@ -543,6 +588,8 @@ export function ansiLogToHTML(line) {
   cursor: pointer;
   padding: 5px 10px;
   display: flex;
+  align-items: center;
+  user-select: none;
 }
 
 .job-step-container .job-step-summary .step-summary-msg {
@@ -553,8 +600,25 @@ export function ansiLogToHTML(line) {
   margin-left: 16px;
 }
 
-.job-step-container .job-step-summary:hover {
+.job-step-container .job-step-summary:hover,
+.job-step-container .job-step-summary.selected {
+  color: var(--color-console-fg);
   background-color: var(--color-black-light);
+  border-radius: 5px;
+}
+
+@media (max-width: 768px) {
+  .action-view-body {
+    flex-direction: column;
+  }
+  .action-view-left, .action-view-right {
+    width: 100%;
+  }
+
+  .action-view-left {
+    max-width: none;
+    overflow-y: hidden;
+  }
 }
 </style>
 
@@ -576,12 +640,19 @@ export function ansiLogToHTML(line) {
 
 .job-step-section .job-step-logs {
   font-family: monospace, monospace;
+  margin: 8px 0px;
+  font-size: 12px;
 }
 
 .job-step-section .job-step-logs .job-log-line {
   display: flex;
 }
 
+.job-step-section .job-step-logs .job-log-line:hover {
+  color: var(--color-console-fg);
+  background-color: var(--color-console-hover-bg);
+}
+
 .job-step-section .job-step-logs .job-log-line .line-num {
   width: 48px;
   color: var(--color-grey-light);