diff --git a/models/actions/run_list.go b/models/actions/run_list.go index 56de8eb916..29ab193d57 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -71,6 +71,7 @@ type FindRunOptions struct { WorkflowFileName string TriggerUserID int64 Approved bool // not util.OptionalBool, it works only when it's true + Status Status } func (opts FindRunOptions) toConds() builder.Cond { @@ -90,6 +91,9 @@ func (opts FindRunOptions) toConds() builder.Cond { if opts.Approved { cond = cond.And(builder.Gt{"approved_by": 0}) } + if opts.Status > StatusUnknown { + cond = cond.And(builder.Eq{"status": opts.Status}) + } return cond } @@ -106,3 +110,34 @@ func FindRuns(ctx context.Context, opts FindRunOptions) (RunList, int64, error) func CountRuns(ctx context.Context, opts FindRunOptions) (int64, error) { return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionRun)) } + +type StatusInfo struct { + Status int + DisplayedStatus string +} + +// GetStatusInfoList returns a slice of StatusInfo +func GetStatusInfoList(ctx context.Context) []StatusInfo { + // same as those in aggregateJobStatus + allStatus := []Status{StatusSuccess, StatusFailure, StatusWaiting, StatusRunning} + statusInfoList := make([]StatusInfo, 0, 4) + for _, s := range allStatus { + statusInfoList = append(statusInfoList, StatusInfo{ + Status: int(s), + DisplayedStatus: s.String(), + }) + } + return statusInfoList +} + +// GetActors returns a slice of Actors +func GetActors(ctx context.Context, repoID int64) ([]*user_model.User, error) { + actors := make([]*user_model.User, 0, 10) + + return actors, db.GetEngine(ctx).Where(builder.In("id", builder.Select("`action_run`.trigger_user_id").From("`action_run`"). + GroupBy("`action_run`.trigger_user_id"). + Where(builder.Eq{"`action_run`.repo_id": repoID}))). + Cols("id", "name", "full_name", "avatar", "avatar_email", "use_custom_avatar"). + OrderBy(user_model.GetOrderByName()). + Find(&actors) +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 0cf8810702..234b898fc1 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3460,6 +3460,12 @@ runs.commit = Commit runs.pushed_by = Pushed by runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s runs.no_matching_runner_helper = No matching runner: %s +runs.actor = Actor +runs.status = Status +runs.actors_no_select = All actors +runs.status_no_select = All status +runs.no_results = No results matched. +runs.no_runs = The workflow has no runs yet. need_approval_desc = Need approval to run workflows for fork pull request. diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go index 10acb46854..e1e07b5a72 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -5,6 +5,7 @@ package actions import ( "bytes" + "fmt" "net/http" actions_model "code.gitea.io/gitea/models/actions" @@ -16,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/routers/web/repo" "code.gitea.io/gitea/services/convert" "github.com/nektos/act/pkg/model" @@ -125,7 +127,16 @@ func List(ctx *context.Context) { } workflow := ctx.FormString("workflow") + actorID := ctx.FormInt64("actor") + status := ctx.FormInt("status") ctx.Data["CurWorkflow"] = workflow + // if status or actor query param is not given to frontend href, (href="//actions") + // they will be 0 by default, which indicates get all status or actors + ctx.Data["CurActor"] = actorID + ctx.Data["CurStatus"] = status + if actorID > 0 || status > int(actions_model.StatusUnknown) { + ctx.Data["IsFiltered"] = true + } opts := actions_model.FindRunOptions{ ListOptions: db.ListOptions{ @@ -134,6 +145,8 @@ func List(ctx *context.Context) { }, RepoID: ctx.Repo.Repository.ID, WorkflowFileName: workflow, + TriggerUserID: actorID, + Status: actions_model.Status(status), } runs, total, err := actions_model.FindRuns(ctx, opts) @@ -153,9 +166,20 @@ func List(ctx *context.Context) { ctx.Data["Runs"] = runs + actors, err := actions_model.GetActors(ctx, ctx.Repo.Repository.ID) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + ctx.Data["Actors"] = repo.MakeSelfOnTop(ctx, actors) + + ctx.Data["StatusInfoList"] = actions_model.GetStatusInfoList(ctx) + pager := context.NewPagination(int(total), opts.PageSize, opts.Page, 5) pager.SetDefaultParams(ctx) pager.AddParamString("workflow", workflow) + pager.AddParamString("actor", fmt.Sprint(actorID)) + pager.AddParamString("status", fmt.Sprint(status)) ctx.Data["Page"] = pager ctx.HTML(http.StatusOK, tplListActions) diff --git a/routers/web/repo/helper.go b/routers/web/repo/helper.go index 6f9ca4874b..fb5ada1bdb 100644 --- a/routers/web/repo/helper.go +++ b/routers/web/repo/helper.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/context" ) -func makeSelfOnTop(ctx *context.Context, users []*user.User) []*user.User { +func MakeSelfOnTop(ctx *context.Context, users []*user.User) []*user.User { if ctx.Doer != nil { sort.Slice(users, func(i, j int) bool { if users[i].ID == users[j].ID { diff --git a/routers/web/repo/helper_test.go b/routers/web/repo/helper_test.go index e9ab44fe69..226e2e81f4 100644 --- a/routers/web/repo/helper_test.go +++ b/routers/web/repo/helper_test.go @@ -13,15 +13,15 @@ import ( ) func TestMakeSelfOnTop(t *testing.T) { - users := makeSelfOnTop(&context.Context{}, []*user.User{{ID: 2}, {ID: 1}}) + users := MakeSelfOnTop(&context.Context{}, []*user.User{{ID: 2}, {ID: 1}}) assert.Len(t, users, 2) assert.EqualValues(t, 2, users[0].ID) - users = makeSelfOnTop(&context.Context{Doer: &user.User{ID: 1}}, []*user.User{{ID: 2}, {ID: 1}}) + users = MakeSelfOnTop(&context.Context{Doer: &user.User{ID: 1}}, []*user.User{{ID: 2}, {ID: 1}}) assert.Len(t, users, 2) assert.EqualValues(t, 1, users[0].ID) - users = makeSelfOnTop(&context.Context{Doer: &user.User{ID: 2}}, []*user.User{{ID: 2}, {ID: 1}}) + users = MakeSelfOnTop(&context.Context{Doer: &user.User{ID: 2}}, []*user.User{{ID: 2}, {ID: 1}}) assert.Len(t, users, 2) assert.EqualValues(t, 2, users[0].ID) } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 49ba753a7d..a9ce1cc1e7 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -312,7 +312,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = makeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) handleTeamMentions(ctx) if ctx.Written() { @@ -508,7 +508,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = makeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) handleTeamMentions(ctx) } @@ -3487,7 +3487,7 @@ func IssuePosters(ctx *context.Context) { } } - posters = makeSelfOnTop(ctx, posters) + posters = MakeSelfOnTop(ctx, posters) resp := &userSearchResponse{} resp.Results = make([]*userSearchInfo, len(posters)) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 309e61cf6e..ef9d5856da 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -809,7 +809,7 @@ func ViewPullFiles(ctx *context.Context) { ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = makeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) handleTeamMentions(ctx) if ctx.Written() { diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index afba1f18bf..5fddddb344 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -349,7 +349,7 @@ func NewRelease(ctx *context.Context) { ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = makeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) upload.AddUploadContext(ctx, "release") ctx.HTML(http.StatusOK, tplReleaseNew) @@ -517,7 +517,7 @@ func EditRelease(ctx *context.Context) { ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = makeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) ctx.HTML(http.StatusOK, tplReleaseNew) } diff --git a/templates/package/shared/list.tmpl b/templates/package/shared/list.tmpl index 707fbe357f..5ac5baf0f1 100644 --- a/templates/package/shared/list.tmpl +++ b/templates/package/shared/list.tmpl @@ -38,7 +38,7 @@ {{else}} {{if not .HasPackages}}
- {{svg "octicon-package" 32}} + {{svg "octicon-package" 48}}

{{.locale.Tr "packages.empty"}}

{{if and .Repository .CanWritePackages}} {{$packagesUrl := URLJoin .Owner.HomeLink "-" "packages"}} diff --git a/templates/repo/actions/list.tmpl b/templates/repo/actions/list.tmpl index ca97b67faa..46cbb34670 100644 --- a/templates/repo/actions/list.tmpl +++ b/templates/repo/actions/list.tmpl @@ -1,14 +1,14 @@ {{template "base/head" .}} -
+
{{template "repo/header" .}}
diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index 5f444f31f9..bfd5aabe55 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -1,4 +1,10 @@
+ {{if eq (len .Runs) 0}} +
+ {{svg "octicon-no-entry" 48}} +

{{if $.IsFiltered}}{{.locale.Tr "actions.runs.no_results"}}{{else}}{{.locale.Tr "actions.runs.no_runs"}}{{end}}

+
+ {{end}} {{range .Runs}}
  • diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 150254569d..fa97393421 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -1877,15 +1877,12 @@ flex: 1 } -.repository.packages .empty { +.repository.packages .empty, +.repository.actions .empty { padding-top: 70px; padding-bottom: 100px; } -.repository.packages .empty .svg { - height: 48px; -} - .repository.packages .file-size { white-space: nowrap; }