0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-13 17:35:18 +02:00

Restyle Workflow Graph (#36912)

Follow GitHub's style and fine tune colors & layouts.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
Nicolas 2026-03-28 10:41:34 +01:00 committed by GitHub
parent 896e4838cb
commit b136a66d12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 385 additions and 489 deletions

View File

@ -68,6 +68,7 @@ func MockActionsRunsJobs(ctx *context.Context) {
runID := ctx.PathParamInt64("run") runID := ctx.PathParamInt64("run")
resp := &actions.ViewResponse{} resp := &actions.ViewResponse{}
resp.State.Run.RepoID = 12345
resp.State.Run.TitleHTML = `mock run title <a href="/">link</a>` resp.State.Run.TitleHTML = `mock run title <a href="/">link</a>`
resp.State.Run.Link = setting.AppSubURL + "/devtest/repo-action-view/runs/" + strconv.FormatInt(runID, 10) 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.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{ resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
ID: runID*10 + 2, ID: runID*10 + 2,
JobID: "job-102", JobID: "job-102",
Name: "job 102", Name: "ULTRA LOOOOOOOOOOOONG job name 102 that exceeds the limit",
Status: actions_model.StatusFailure.String(), Status: actions_model.StatusFailure.String(),
CanRerun: false, CanRerun: false,
Duration: "3h", Duration: "3h",
Needs: []string{"job-100", "job-101"}, 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) fillViewRunResponseCurrentJob(ctx, resp)
ctx.JSON(http.StatusOK, resp) ctx.JSON(http.StatusOK, resp)

View File

@ -129,6 +129,7 @@ type ViewResponse struct {
State struct { State struct {
Run struct { Run struct {
RepoID int64 `json:"repoId"`
Link string `json:"link"` Link string `json:"link"`
Title string `json:"title"` Title string `json:"title"`
TitleHTML template.HTML `json:"titleHTML"` TitleHTML template.HTML `json:"titleHTML"`
@ -252,6 +253,7 @@ func fillViewRunResponseSummary(ctx *context_module.Context, resp *ViewResponse,
return return
} }
resp.State.Run.RepoID = ctx.Repo.Repository.ID
// the title for the "run" is from the commit message // the title for the "run" is from the commit message
resp.State.Run.Title = run.Title resp.State.Run.Title = run.Title
resp.State.Run.TitleHTML = templates.NewRenderUtils(ctx).RenderCommitMessage(run.Title, ctx.Repo.Repository) resp.State.Run.TitleHTML = templates.NewRenderUtils(ctx).RenderCommitMessage(run.Title, ctx.Repo.Repository)

View File

@ -808,9 +808,7 @@ table th[data-sortt-desc] .svg {
.btn, .btn,
.ui.ui.dropdown, .ui.ui.dropdown,
.flex-text-inline, .flex-text-inline {
.flex-text-inline > a,
.flex-text-inline > span {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: var(--gap-inline); gap: var(--gap-inline);

View File

@ -208,7 +208,6 @@ gitea-theme-meta-info {
--color-input-toggle-background: #2e353c; --color-input-toggle-background: #2e353c;
--color-input-border: var(--color-secondary-dark-1); --color-input-border: var(--color-secondary-dark-1);
--color-light: #00001728; --color-light: #00001728;
--color-light-mimic-enabled: rgba(0, 0, 0, calc(40 / 255 * 222 / 255 / var(--opacity-disabled)));
--color-light-border: #e8f3ff28; --color-light-border: #e8f3ff28;
--color-hover: #e8f3ff19; --color-hover: #e8f3ff19;
--color-hover-opaque: #21252a; /* TODO: color-mix(in srgb, var(--color-body), var(--color-hover)); */ --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-danger: var(--color-red);
--color-transparency-grid-light: #2a2a2a; --color-transparency-grid-light: #2a2a2a;
--color-transparency-grid-dark: #1a1a1a; --color-transparency-grid-dark: #1a1a1a;
--color-workflow-edge-hover: #616e78;
accent-color: var(--color-accent); accent-color: var(--color-accent);
color-scheme: dark; color-scheme: dark;
} }

View File

@ -208,7 +208,6 @@ gitea-theme-meta-info {
--color-input-toggle-background: #d0d7de; --color-input-toggle-background: #d0d7de;
--color-input-border: var(--color-secondary-dark-1); --color-input-border: var(--color-secondary-dark-1);
--color-light: #00001706; --color-light: #00001706;
--color-light-mimic-enabled: rgba(0, 0, 0, calc(6 / 255 * 222 / 255 / var(--opacity-disabled)));
--color-light-border: #0000171d; --color-light-border: #0000171d;
--color-hover: #00001708; --color-hover: #00001708;
--color-hover-opaque: #f1f3f5; /* TODO: color-mix(in srgb, var(--color-body), var(--color-hover)); */ --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-danger: var(--color-red);
--color-transparency-grid-light: #fafafa; --color-transparency-grid-light: #fafafa;
--color-transparency-grid-dark: #e2e2e2; --color-transparency-grid-dark: #e2e2e2;
--color-workflow-edge-hover: #b1b7bd;
accent-color: var(--color-accent); accent-color: var(--color-accent);
color-scheme: light; color-scheme: light;
} }

View File

@ -29,35 +29,42 @@ onBeforeUnmount(() => {
}); });
</script> </script>
<template> <template>
<div> <div class="action-run-summary-view">
<div class="action-run-summary-block"> <div class="action-run-summary-block">
<p class="action-run-summary-trigger"> <div class="flex-text-block">
{{ locale.triggeredVia.replace('%s', run.triggerEvent) }} {{ locale.triggeredVia.replace('%s', run.triggerEvent) }} <relative-time :datetime="runTriggeredAtIso" prefix=""/>
&nbsp;&nbsp;<relative-time :datetime="runTriggeredAtIso" prefix=" "/> </div>
</p> <div class="flex-text-block">
<p class="tw-mb-0">
<ActionRunStatus :locale-status="locale.status[run.status]" :status="run.status" :size="16"/> <ActionRunStatus :locale-status="locale.status[run.status]" :status="run.status" :size="16"/>
<span class="tw-ml-2">{{ locale.status[run.status] }}</span> <span>{{ locale.status[run.status] }}</span> <span>{{ locale.totalDuration }} {{ run.duration || '' }}</span>
<span class="tw-ml-3">{{ locale.totalDuration }} {{ run.duration || '' }}</span> </div>
</p>
</div> </div>
<WorkflowGraph <WorkflowGraph
v-if="run.jobs.length > 0" v-if="run.jobs.length > 0"
:store="store"
:jobs="run.jobs" :jobs="run.jobs"
:run-link="run.link" :run-link="run.link"
:workflow-id="run.workflowID" :workflow-id="run.workflowID"
class="workflow-graph-container"
/> />
</div> </div>
</template> </template>
<style scoped> <style scoped>
.action-run-summary-block { .action-run-summary-view {
padding: 12px; flex: 1;
border-bottom: 1px solid var(--color-secondary); display: flex;
flex-direction: column;
color: var(--color-text-light-1);
} }
.action-run-summary-trigger { .action-run-summary-block {
margin-bottom: 6px; display: flex;
color: var(--color-text-light-2); justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 6px;
padding: 12px;
border-bottom: 1px solid var(--color-secondary);
border-radius: var(--border-radius) var(--border-radius) 0 0;
background: var(--color-box-header);
} }
</style> </style>

View File

@ -89,6 +89,7 @@ export function createLogLineMessage(line: LogLine, cmd: LogLineCommand | null)
export function createEmptyActionsRun(): ActionsRun { export function createEmptyActionsRun(): ActionsRun {
return { return {
repoId: 0,
link: '', link: '',
title: '', title: '',
titleHTML: '', titleHTML: '',

View File

@ -222,7 +222,11 @@ async function deleteArtifact(name: string) {
max-width: 400px; max-width: 400px;
position: sticky; position: sticky;
top: 12px; 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; overflow-y: auto;
background: var(--color-body); background: var(--color-body);
z-index: 2; /* above .job-info-header */ z-index: 2; /* above .job-info-header */
@ -231,12 +235,13 @@ async function deleteArtifact(name: string) {
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
.action-view-left { .action-view-left {
position: static; /* can not sticky because multiple jobs would overlap into right view */ position: static; /* can not sticky because multiple jobs would overlap into right view */
max-height: unset;
} }
} }
.left-list-header { .left-list-header {
font-size: 12px; font-size: 13px;
color: var(--color-grey); color: var(--color-text-light-2);
} }
.job-artifacts-item { .job-artifacts-item {
@ -299,7 +304,6 @@ async function deleteArtifact(name: string) {
.job-brief-item .job-brief-item-left .job-brief-name { .job-brief-item .job-brief-item-left .job-brief-name {
display: block; display: block;
width: 70%;
} }
.job-brief-item .job-brief-item-right { .job-brief-item .job-brief-item-right {
@ -320,7 +324,6 @@ async function deleteArtifact(name: string) {
border: 1px solid var(--color-console-border); border: 1px solid var(--color-console-border);
border-radius: var(--border-radius); border-radius: var(--border-radius);
background: var(--color-console-bg); background: var(--color-console-bg);
align-self: flex-start;
} }
/* begin fomantic button overrides */ /* begin fomantic button overrides */

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@ import RepoActionView from '../components/RepoActionView.vue';
export function initRepositoryActionView() { export function initRepositoryActionView() {
const el = document.querySelector('#repo-action-view'); const el = document.querySelector('#repo-action-view');
if (!el) return; if (!el) return;
const runId = parseInt(el.getAttribute('data-run-id')!);
const jobId = parseInt(el.getAttribute('data-job-id')!);
// TODO: the parent element's full height doesn't work well now, // TODO: the parent element's full height doesn't work well now,
// but we can not pollute the global style at the moment, only fix the height problem for pages with this component // but we can not pollute the global style at the moment, only fix the height problem for pages with this component
@ -11,8 +13,8 @@ export function initRepositoryActionView() {
if (parentFullHeight) parentFullHeight.classList.add('tw-pb-0'); if (parentFullHeight) parentFullHeight.classList.add('tw-pb-0');
const view = createApp(RepoActionView, { const view = createApp(RepoActionView, {
runId: parseInt(el.getAttribute('data-run-id')!), runId,
jobId: parseInt(el.getAttribute('data-job-id')!), jobId,
actionsUrl: el.getAttribute('data-actions-url'), actionsUrl: el.getAttribute('data-actions-url'),
locale: { locale: {
approve: el.getAttribute('data-locale-approve'), approve: el.getAttribute('data-locale-approve'),

View File

@ -2,6 +2,7 @@
export type ActionsRunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked'; export type ActionsRunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked';
export type ActionsRun = { export type ActionsRun = {
repoId: number,
link: string, link: string,
title: string, title: string,
titleHTML: string, titleHTML: string,