diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json
index 72cdfbc40f..97e2ebe0d1 100644
--- a/options/locale/locale_en-US.json
+++ b/options/locale/locale_en-US.json
@@ -3695,6 +3695,7 @@
"actions.runs.delete.description": "Are you sure you want to permanently delete this workflow run? This action cannot be undone.",
"actions.runs.not_done": "This workflow run is not done.",
"actions.runs.view_workflow_file": "View workflow file",
+ "actions.runs.workflow_graph": "Workflow Graph",
"actions.workflow.disable": "Disable Workflow",
"actions.workflow.disable_success": "Workflow '%s' disabled successfully.",
"actions.workflow.enable": "Enable Workflow",
diff --git a/routers/web/devtest/mock_actions.go b/routers/web/devtest/mock_actions.go
index 90c6f99d5e..7a71dad804 100644
--- a/routers/web/devtest/mock_actions.go
+++ b/routers/web/devtest/mock_actions.go
@@ -12,6 +12,7 @@ import (
"time"
actions_model "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/web/repo/actions"
@@ -58,8 +59,8 @@ func generateMockStepsLog(logCur actions.LogCursor, opts generateMockStepsLogOpt
}
func MockActionsView(ctx *context.Context) {
- ctx.Data["RunID"] = ctx.PathParam("run")
- ctx.Data["JobID"] = ctx.PathParam("job")
+ ctx.Data["RunIndex"] = ctx.PathParam("run")
+ ctx.Data["JobIndex"] = ctx.PathParam("job")
ctx.HTML(http.StatusOK, "devtest/repo-action-view")
}
@@ -69,6 +70,7 @@ func MockActionsRunsJobs(ctx *context.Context) {
req := web.GetForm(ctx).(*actions.ViewRequest)
resp := &actions.ViewResponse{}
resp.State.Run.TitleHTML = `mock run title link`
+ resp.State.Run.Link = setting.AppSubURL + "/devtest/repo-action-view/runs/" + strconv.FormatInt(runID, 10)
resp.State.Run.Status = actions_model.StatusRunning.String()
resp.State.Run.CanCancel = runID == 10
resp.State.Run.CanApprove = runID == 20
@@ -112,6 +114,7 @@ func MockActionsRunsJobs(ctx *context.Context) {
resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
ID: runID * 10,
+ JobID: "job-100",
Name: "job 100",
Status: actions_model.StatusRunning.String(),
CanRerun: true,
@@ -119,17 +122,21 @@ func MockActionsRunsJobs(ctx *context.Context) {
})
resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
ID: runID*10 + 1,
+ JobID: "job-101",
Name: "job 101",
Status: actions_model.StatusWaiting.String(),
CanRerun: false,
Duration: "2h",
+ Needs: []string{"job-100"},
})
resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
ID: runID*10 + 2,
+ JobID: "job-102",
Name: "job 102",
Status: actions_model.StatusFailure.String(),
CanRerun: false,
Duration: "3h",
+ Needs: []string{"job-100", "job-101"},
})
var mockLogOptions []generateMockStepsLogOptions
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index 2efcfc84fa..33c1e73aa4 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -143,11 +143,13 @@ type ViewResponse struct {
}
type ViewJob struct {
- ID int64 `json:"id"`
- Name string `json:"name"`
- Status string `json:"status"`
- CanRerun bool `json:"canRerun"`
- Duration string `json:"duration"`
+ ID int64 `json:"id"`
+ JobID string `json:"jobId,omitempty"`
+ Name string `json:"name"`
+ Status string `json:"status"`
+ CanRerun bool `json:"canRerun"`
+ Duration string `json:"duration"`
+ Needs []string `json:"needs,omitempty"`
}
type ViewCommit struct {
@@ -248,10 +250,12 @@ func ViewPost(ctx *context_module.Context) {
for _, v := range jobs {
resp.State.Run.Jobs = append(resp.State.Run.Jobs, &ViewJob{
ID: v.ID,
+ JobID: v.JobID,
Name: v.Name,
Status: v.Status.String(),
CanRerun: resp.State.Run.CanRerun,
Duration: v.Duration().String(),
+ Needs: v.Needs,
})
}
diff --git a/routers/web/web.go b/routers/web/web.go
index 9e6354e138..b1b31a7ec9 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1675,7 +1675,7 @@ func registerWebRoutes(m *web.Router) {
m.Any("/mail-preview", devtest.MailPreview)
m.Any("/mail-preview/*", devtest.MailPreviewRender)
m.Any("/{sub}", devtest.TmplCommon)
- m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView)
+ m.Get("/repo-action-view/runs/{run}/jobs/{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 677eccc062..292c84c928 100644
--- a/templates/devtest/repo-action-view.tmpl
+++ b/templates/devtest/repo-action-view.tmpl
@@ -1,13 +1,13 @@
{{template "base/head" .}}
{{template "repo/actions/view_component" (dict
- "RunIndex" (or .RunID 10)
- "JobIndex" (or .JobID 100)
+ "RunIndex" (or .RunIndex 10)
+ "JobIndex" (or .JobIndex 0)
"ActionsURL" (print AppSubUrl "/devtest/actions-mock")
)}}
diff --git a/templates/repo/actions/view_component.tmpl b/templates/repo/actions/view_component.tmpl
index 4e338ffcfc..ebe5158c8a 100644
--- a/templates/repo/actions/view_component.tmpl
+++ b/templates/repo/actions/view_component.tmpl
@@ -10,6 +10,7 @@
data-locale-runs-scheduled="{{ctx.Locale.Tr "actions.runs.scheduled"}}"
data-locale-runs-commit="{{ctx.Locale.Tr "actions.runs.commit"}}"
data-locale-runs-pushed-by="{{ctx.Locale.Tr "actions.runs.pushed_by"}}"
+ data-locale-runs-workflow-graph="{{ctx.Locale.Tr "actions.runs.workflow_graph"}}"
data-locale-status-unknown="{{ctx.Locale.Tr "actions.status.unknown"}}"
data-locale-status-waiting="{{ctx.Locale.Tr "actions.status.waiting"}}"
data-locale-status-running="{{ctx.Locale.Tr "actions.status.running"}}"
diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css
index 1969b52ed1..8766bf7abc 100644
--- a/web_src/css/themes/theme-gitea-light.css
+++ b/web_src/css/themes/theme-gitea-light.css
@@ -66,14 +66,14 @@ gitea-theme-meta-info {
--color-secondary-hover: var(--color-secondary-dark-5);
--color-secondary-active: var(--color-secondary-dark-6);
/* console colors - used for actions console and console files */
- --color-console-fg: #f7f8f9;
- --color-console-fg-subtle: #bdc4cc;
- --color-console-bg: #171b1e;
- --color-console-border: #2e353b;
- --color-console-hover-bg: #272d33;
- --color-console-active-bg: #2e353b;
- --color-console-menu-bg: #262b31;
- --color-console-menu-border: #414b55;
+ --color-console-fg: #0d1117;
+ --color-console-fg-subtle: #40474d;
+ --color-console-bg: #ffffff;
+ --color-console-border: #d0d7de;
+ --color-console-hover-bg: #f1f3f5;
+ --color-console-active-bg: #d0d7de;
+ --color-console-menu-bg: #f8f9fb;
+ --color-console-menu-border: #d0d7de;
/* named colors */
--color-red: #db2828;
--color-orange: #f2711c;
diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue
index b43d025b2d..efa3472e8c 100644
--- a/web_src/js/components/RepoActionView.vue
+++ b/web_src/js/components/RepoActionView.vue
@@ -8,10 +8,9 @@ import {renderAnsi} from '../render/ansi.ts';
import {POST, DELETE} from '../modules/fetch.ts';
import type {IntervalId} from '../types.ts';
import {toggleFullScreen} from '../utils.ts';
+import WorkflowGraph from './WorkflowGraph.vue'
import {localUserSettings} from '../modules/user-settings.ts';
-
-// see "models/actions/status.go", if it needs to be used somewhere else, move it to a shared file like "types/actions.ts"
-type RunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked';
+import type {ActionsRunStatus, ActionsJob} from '../modules/gitea-actions.ts';
type StepContainerElement = HTMLElement & {
// To remember the last active logs container, for example: a batch of logs only starts a group but doesn't end it,
@@ -54,19 +53,10 @@ const LogLinePrefixCommandMap: Record = {
'::remove-matcher': 'hidden', // it has arguments
};
-
-type Job = {
- id: number;
- name: string;
- status: RunStatus;
- canRerun: boolean;
- duration: string;
-}
-
type Step = {
summary: string,
duration: string,
- status: RunStatus,
+ status: ActionsRunStatus,
}
type JobStepState = {
@@ -107,6 +97,7 @@ function isLogElementInViewport(el: Element, {extraViewPortHeight}={extraViewPor
type LocaleStorageOptions = {
autoScroll: boolean;
expandRunning: boolean;
+ showWorkflowGraph: boolean;
actionsLogShowSeconds: boolean;
actionsLogShowTimestamps: boolean;
};
@@ -116,20 +107,12 @@ export default defineComponent({
components: {
SvgIcon,
ActionRunStatus,
+ WorkflowGraph,
},
props: {
- runIndex: {
- type: String,
- default: '',
- },
- jobIndex: {
- type: String,
- default: '',
- },
- actionsURL: {
- type: String,
- default: '',
- },
+ runIndex: {type: Number, required: true},
+ jobIndex: {type: Number, required: true},
+ actionsURL: {type: String, required: true},
locale: {
type: Object as PropType>,
default: null,
@@ -137,8 +120,8 @@ export default defineComponent({
},
data() {
- const defaultViewOptions: LocaleStorageOptions = {autoScroll: true, expandRunning: false, actionsLogShowSeconds: false, actionsLogShowTimestamps: false};
- const {autoScroll, expandRunning, actionsLogShowSeconds, actionsLogShowTimestamps} = localUserSettings.getJsonObject('actions-view-options', defaultViewOptions);
+ const defaultViewOptions: LocaleStorageOptions = {autoScroll: true, expandRunning: false, showWorkflowGraph: false, actionsLogShowSeconds: false, actionsLogShowTimestamps: false};
+ const {autoScroll, expandRunning, showWorkflowGraph, actionsLogShowSeconds, actionsLogShowTimestamps} = localUserSettings.getJsonObject('actions-view-options', defaultViewOptions);
return {
// internal state
loadingAbortController: null as AbortController | null,
@@ -147,6 +130,7 @@ export default defineComponent({
artifacts: [] as Array>,
menuVisible: false,
isFullScreen: false,
+ showWorkflowGraph: showWorkflowGraph,
timeVisible: {
'log-time-stamp': actionsLogShowTimestamps,
'log-time-seconds': actionsLogShowSeconds,
@@ -159,7 +143,7 @@ export default defineComponent({
link: '',
title: '',
titleHTML: '',
- status: '' as RunStatus, // do not show the status before initialized, otherwise it would show an incorrect "error" icon
+ status: '' as ActionsRunStatus, // do not show the status before initialized, otherwise it would show an incorrect "error" icon
canCancel: false,
canApprove: false,
canRerun: false,
@@ -176,7 +160,7 @@ export default defineComponent({
// canRerun: false,
// duration: '',
// },
- ] as Array,
+ ] as Array,
commit: {
localeCommit: '',
localePushedBy: '',
@@ -214,6 +198,9 @@ export default defineComponent({
optionAlwaysExpandRunning() {
this.saveLocaleStorageOptions();
},
+ showWorkflowGraph() {
+ this.saveLocaleStorageOptions();
+ },
},
async mounted() {
@@ -258,6 +245,7 @@ export default defineComponent({
const opts: LocaleStorageOptions = {
autoScroll: this.optionAlwaysAutoScroll,
expandRunning: this.optionAlwaysExpandRunning,
+ showWorkflowGraph: this.showWorkflowGraph,
actionsLogShowSeconds: this.timeVisible['log-time-seconds'],
actionsLogShowTimestamps: this.timeVisible['log-time-stamp'],
};
@@ -456,11 +444,11 @@ export default defineComponent({
}
},
- isDone(status: RunStatus) {
+ isDone(status: ActionsRunStatus) {
return ['success', 'skipped', 'failure', 'cancelled'].includes(status);
},
- isExpandable(status: RunStatus) {
+ isExpandable(status: ActionsRunStatus) {
return ['success', 'running', 'failure', 'cancelled'].includes(status);
},
@@ -514,15 +502,20 @@ export default defineComponent({
-
-
-
+
+
+
+
+
+