From b136a66d123a2a7d456775aeccc50086a3432ea2 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sat, 28 Mar 2026 10:41:34 +0100 Subject: [PATCH] Restyle Workflow Graph (#36912) Follow GitHub's style and fine tune colors & layouts. Co-authored-by: Claude Sonnet 4.6 Co-authored-by: wxiaoguang Co-authored-by: silverwind --- routers/web/devtest/mock_actions.go | 27 +- routers/web/repo/actions/view.go | 2 + web_src/css/base.css | 4 +- web_src/css/themes/theme-gitea-dark.css | 2 +- web_src/css/themes/theme-gitea-light.css | 2 +- .../js/components/ActionRunSummaryView.vue | 39 +- web_src/js/components/ActionRunView.ts | 1 + web_src/js/components/RepoActionView.vue | 13 +- web_src/js/components/WorkflowGraph.vue | 777 +++++++----------- web_src/js/features/repo-actions.ts | 6 +- web_src/js/modules/gitea-actions.ts | 1 + 11 files changed, 385 insertions(+), 489 deletions(-) diff --git a/routers/web/devtest/mock_actions.go b/routers/web/devtest/mock_actions.go index 00ca095e71..0fb2a35824 100644 --- a/routers/web/devtest/mock_actions.go +++ b/routers/web/devtest/mock_actions.go @@ -68,6 +68,7 @@ func MockActionsRunsJobs(ctx *context.Context) { runID := ctx.PathParamInt64("run") resp := &actions.ViewResponse{} + resp.State.Run.RepoID = 12345 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() @@ -135,12 +136,36 @@ func MockActionsRunsJobs(ctx *context.Context) { resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{ ID: runID*10 + 2, JobID: "job-102", - Name: "job 102", + Name: "ULTRA LOOOOOOOOOOOONG job name 102 that exceeds the limit", Status: actions_model.StatusFailure.String(), CanRerun: false, Duration: "3h", Needs: []string{"job-100", "job-101"}, }) + resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{ + ID: runID*10 + 3, + JobID: "job-103", + Name: "job 103", + Status: actions_model.StatusCancelled.String(), + CanRerun: false, + Duration: "2m", + Needs: []string{"job-100"}, + }) + + // add more jobs to a run for UI testing + if resp.State.Run.CanCancel { + for i := range 10 { + resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{ + ID: runID*1000 + int64(i), + JobID: "job-dup-test-" + strconv.Itoa(i), + Name: "job dup test " + strconv.Itoa(i), + Status: actions_model.StatusSuccess.String(), + CanRerun: false, + Duration: "2m", + Needs: []string{"job-103", "job-101", "job-100"}, + }) + } + } fillViewRunResponseCurrentJob(ctx, resp) ctx.JSON(http.StatusOK, resp) diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 90810a6d25..6b3e95f3da 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -129,6 +129,7 @@ type ViewResponse struct { State struct { Run struct { + RepoID int64 `json:"repoId"` Link string `json:"link"` Title string `json:"title"` TitleHTML template.HTML `json:"titleHTML"` @@ -252,6 +253,7 @@ func fillViewRunResponseSummary(ctx *context_module.Context, resp *ViewResponse, return } + resp.State.Run.RepoID = ctx.Repo.Repository.ID // the title for the "run" is from the commit message resp.State.Run.Title = run.Title resp.State.Run.TitleHTML = templates.NewRenderUtils(ctx).RenderCommitMessage(run.Title, ctx.Repo.Repository) diff --git a/web_src/css/base.css b/web_src/css/base.css index b4139c0e72..60317887ba 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -808,9 +808,7 @@ table th[data-sortt-desc] .svg { .btn, .ui.ui.dropdown, -.flex-text-inline, -.flex-text-inline > a, -.flex-text-inline > span { +.flex-text-inline { display: inline-flex; align-items: center; gap: var(--gap-inline); diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 610e5f1344..28dd878481 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -208,7 +208,6 @@ gitea-theme-meta-info { --color-input-toggle-background: #2e353c; --color-input-border: var(--color-secondary-dark-1); --color-light: #00001728; - --color-light-mimic-enabled: rgba(0, 0, 0, calc(40 / 255 * 222 / 255 / var(--opacity-disabled))); --color-light-border: #e8f3ff28; --color-hover: #e8f3ff19; --color-hover-opaque: #21252a; /* TODO: color-mix(in srgb, var(--color-body), var(--color-hover)); */ @@ -249,6 +248,7 @@ gitea-theme-meta-info { --color-danger: var(--color-red); --color-transparency-grid-light: #2a2a2a; --color-transparency-grid-dark: #1a1a1a; + --color-workflow-edge-hover: #616e78; accent-color: var(--color-accent); color-scheme: dark; } diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index 0885c5618b..6576b88987 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -208,7 +208,6 @@ gitea-theme-meta-info { --color-input-toggle-background: #d0d7de; --color-input-border: var(--color-secondary-dark-1); --color-light: #00001706; - --color-light-mimic-enabled: rgba(0, 0, 0, calc(6 / 255 * 222 / 255 / var(--opacity-disabled))); --color-light-border: #0000171d; --color-hover: #00001708; --color-hover-opaque: #f1f3f5; /* TODO: color-mix(in srgb, var(--color-body), var(--color-hover)); */ @@ -249,6 +248,7 @@ gitea-theme-meta-info { --color-danger: var(--color-red); --color-transparency-grid-light: #fafafa; --color-transparency-grid-dark: #e2e2e2; + --color-workflow-edge-hover: #b1b7bd; accent-color: var(--color-accent); color-scheme: light; } diff --git a/web_src/js/components/ActionRunSummaryView.vue b/web_src/js/components/ActionRunSummaryView.vue index 2d79a82288..48af966c94 100644 --- a/web_src/js/components/ActionRunSummaryView.vue +++ b/web_src/js/components/ActionRunSummaryView.vue @@ -29,35 +29,42 @@ onBeforeUnmount(() => { }); diff --git a/web_src/js/components/ActionRunView.ts b/web_src/js/components/ActionRunView.ts index 250f39e811..133b7263eb 100644 --- a/web_src/js/components/ActionRunView.ts +++ b/web_src/js/components/ActionRunView.ts @@ -89,6 +89,7 @@ export function createLogLineMessage(line: LogLine, cmd: LogLineCommand | null) export function createEmptyActionsRun(): ActionsRun { return { + repoId: 0, link: '', title: '', titleHTML: '', diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 4ced86b523..3637763b90 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -222,7 +222,11 @@ async function deleteArtifact(name: string) { max-width: 400px; position: sticky; top: 12px; - max-height: 100vh; + + /* about 12px top padding + 12px bottom padding + 37px footer height, + TODO: need to use JS to calculate the height for better scrolling experience*/ + max-height: calc(100vh - 62px); + overflow-y: auto; background: var(--color-body); z-index: 2; /* above .job-info-header */ @@ -231,12 +235,13 @@ async function deleteArtifact(name: string) { @media (max-width: 767.98px) { .action-view-left { position: static; /* can not sticky because multiple jobs would overlap into right view */ + max-height: unset; } } .left-list-header { - font-size: 12px; - color: var(--color-grey); + font-size: 13px; + color: var(--color-text-light-2); } .job-artifacts-item { @@ -299,7 +304,6 @@ async function deleteArtifact(name: string) { .job-brief-item .job-brief-item-left .job-brief-name { display: block; - width: 70%; } .job-brief-item .job-brief-item-right { @@ -320,7 +324,6 @@ async function deleteArtifact(name: string) { border: 1px solid var(--color-console-border); border-radius: var(--border-radius); background: var(--color-console-bg); - align-self: flex-start; } /* begin fomantic button overrides */ diff --git a/web_src/js/components/WorkflowGraph.vue b/web_src/js/components/WorkflowGraph.vue index c311b87d98..06ac1686e6 100644 --- a/web_src/js/components/WorkflowGraph.vue +++ b/web_src/js/components/WorkflowGraph.vue @@ -1,31 +1,31 @@