From 54d952ee66a00deb497eb629651b30e3599b8948 Mon Sep 17 00:00:00 2001 From: Robert Wolff Date: Wed, 11 Feb 2026 03:22:53 +0100 Subject: [PATCH] feat(ui): support additional job status selection in dropdown menu on Actions tab (#11156) ### Tests - I added test coverage for Go changes... - [x] in their respective `*_test.go` for unit tests. - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [x] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [x] I did not document these changes and I do not expect someone else to do it. ### Release notes - [x] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change. - [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change. ### Disclaimer Generative AI (ChatGPT) was used to debug the e2e test, with copied code lines below threshold of originality. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11156 Reviewed-by: Gusted Reviewed-by: Mathieu Fenniak Reviewed-by: Andreas Ahlenstorf Co-authored-by: Robert Wolff Co-committed-by: Robert Wolff --- models/actions/run_list.go | 11 ++++++++-- models/actions/run_list_test.go | 37 +++++++++++++++++++++++++++++++++ tests/e2e/actions.test.e2e.ts | 18 +++++++++++----- 3 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 models/actions/run_list_test.go diff --git a/models/actions/run_list.go b/models/actions/run_list.go index a450212185..b296e2f477 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -5,6 +5,7 @@ package actions import ( "context" + "slices" "forgejo.org/models/db" repo_model "forgejo.org/models/repo" @@ -13,6 +14,8 @@ import ( "forgejo.org/modules/translation" webhook_module "forgejo.org/modules/webhook" + "golang.org/x/text/collate" + "golang.org/x/text/language" "xorm.io/builder" ) @@ -127,14 +130,18 @@ type StatusInfo struct { // GetStatusInfoList returns a slice of StatusInfo func GetStatusInfoList(ctx context.Context, lang translation.Locale) []StatusInfo { // same as those in aggregateJobStatus - allStatus := []Status{StatusSuccess, StatusFailure, StatusWaiting, StatusRunning} - statusInfoList := make([]StatusInfo, 0, 4) + allStatus := []Status{StatusBlocked, StatusCancelled, StatusFailure, StatusRunning, StatusSkipped, StatusSuccess, StatusWaiting} + statusInfoList := make([]StatusInfo, 0, 7) for _, s := range allStatus { statusInfoList = append(statusInfoList, StatusInfo{ Status: int(s), DisplayedStatus: s.LocaleString(lang), }) } + collator := collate.New(language.Und, collate.IgnoreCase) + slices.SortFunc(statusInfoList, func(a, b StatusInfo) int { + return collator.CompareString(a.DisplayedStatus, b.DisplayedStatus) + }) return statusInfoList } diff --git a/models/actions/run_list_test.go b/models/actions/run_list_test.go new file mode 100644 index 0000000000..b3d22b5155 --- /dev/null +++ b/models/actions/run_list_test.go @@ -0,0 +1,37 @@ +// Copyright 2026 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-or-later + +package actions + +import ( + "testing" + + "forgejo.org/models/unittest" + "forgejo.org/modules/translation" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestActionStatusList(t *testing.T) { + require.NoError(t, unittest.PrepareTestDatabase()) + translation.InitLocales(t.Context()) + + statusInfoList := GetStatusInfoList(t.Context(), translation.NewLocale("en-US")) + assert.Len(t, statusInfoList, 7) + statuses := []string{"Blocked", "Canceled", "Failure", "Running", "Skipped", "Success", "Waiting"} + statusInts := []int{7, 3, 2, 6, 4, 1, 5} + for i, statusString := range statuses { + assert.Equal(t, statusInfoList[i].Status, statusInts[i]) + assert.Equal(t, statusInfoList[i].DisplayedStatus, statusString) + } + + statusInfoList = GetStatusInfoList(t.Context(), translation.NewLocale("de-DE")) + assert.Len(t, statusInfoList, 7) + statuses = []string{"Abgebrochen", "Blockiert", "Erfolg", "Fehler", "Laufend", "Übersprungen", "Wartend"} + statusInts = []int{3, 7, 1, 2, 6, 4, 5} + for i, statusString := range statuses { + assert.Equal(t, statusInfoList[i].Status, statusInts[i]) + assert.Equal(t, statusInfoList[i].DisplayedStatus, statusString) + } +} diff --git a/tests/e2e/actions.test.e2e.ts b/tests/e2e/actions.test.e2e.ts index 2f5d09e561..8981d037d3 100644 --- a/tests/e2e/actions.test.e2e.ts +++ b/tests/e2e/actions.test.e2e.ts @@ -203,11 +203,19 @@ test.describe('workflow list dynamic refresh', () => { await page.locator('#workflow_dispatch_dropdown>button').click(); // Status dropdown - await expect(page.getByText('Waiting')).toBeHidden(); - await expect(page.getByText('Failure')).toBeHidden(); - await page.locator('#status_dropdown').click(); - await expect(page.getByText('Waiting')).toBeVisible(); - await expect(page.getByText('Failure')).toBeVisible(); + const dropdown = page.locator('#status_dropdown'); + const dropdown_menu = dropdown.locator('.menu'); + await expect(dropdown_menu).toBeHidden(); + await dropdown.click(); + await expect(dropdown_menu).toBeVisible(); + await expect(dropdown_menu.getByText('All status')).toHaveAttribute('href', /&status=0$/); + await expect(dropdown_menu.getByText('Success')).toHaveAttribute('href', /&status=1$/); + await expect(dropdown_menu.getByText('Failure')).toHaveAttribute('href', /&status=2$/); + await expect(dropdown_menu.getByText('Waiting')).toHaveAttribute('href', /&status=5$/); + await expect(dropdown_menu.getByText('Running')).toHaveAttribute('href', /&status=6$/); + await expect(dropdown_menu.getByText('Blocked')).toHaveAttribute('href', /&status=7$/); + await expect(dropdown_menu.getByText('Canceled')).toHaveAttribute('href', /&status=3$/); + await expect(dropdown_menu.getByText('Skipped')).toHaveAttribute('href', /&status=4$/); // Actor dropdown await expect(page.getByText('All actors')).toBeHidden();