Compare commits

...
6 Commits
Author SHA1 Message Date
silverwindandGitHub 8ba4f05eae Merge branch 'main' into renovate/python-dependencies 2026-07-15 08:24:12 +02:00
9fa2bff5fd fix(admin): exit dev test queue producer loop when context is cancelled (#38451)
Co-authored-by: Kadajett <jeremy@semfora.ai>
2026-07-15 03:25:50 +00:00
880ddb5724 fix(actions): prevent bulk actions from affecting all runners (#38453)
Fix the bug in the site-admin runner bulk actions introduced by #37869:
the runner IDs are empty then all runners will be deleted.

Fixes #38449

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-15 02:36:03 +00:00
GiteaBot 7c629e1ba7 [skip ci] Updated translations via Crowdin 2026-07-15 00:45:33 +00:00
b6904c9730 fix: make "test push webhook" always work (#38425)
* fix #38309
* fix #26238
* fix #37886

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-14 18:24:18 +00:00
9c08df8bc8 fix(org): align follow button and wrap description (#38448)
### Description
Fixes the organization page header layout issue where:
1. Long organization descriptions did not wrap and instead stretched the
header container out of bounds.
2. The "Follow" button floated dynamically adjacent to the description's
right edge depending on the description length, instead of remaining at
a fixed position aligned with the right edge of the page container.

Fixes https://github.com/go-gitea/gitea/issues/38445
### Cause
The flex container `<div class="flex-relaxed-list">` lacked `tw-flex-1`
(to grow to fill the container) and `tw-min-w-0` (to allow it to shrink
below its content's size). Consequently, the flex minimum width
defaulted to `min-content`, stretching the container for long unwrapped
descriptions.

### Solution
Added `tw-flex-1 tw-min-w-0` to the `<div class="flex-relaxed-list">`
container in `templates/org/header.tmpl`. This restricts the width,
enables proper text wrapping, and fixes the "Follow" button to the right
edge of the content container.

### Screenshots
Before
<img width="1300" height="615" alt="image"
src="https://github.com/user-attachments/assets/11e6ab99-b847-45ff-8bdb-8622bfeee8aa"
/>
After
<img width="1300" height="615" alt="image"
src="https://github.com/user-attachments/assets/84ac0633-b192-4be5-8226-13bfad3ab2ec"
/>

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-14 17:54:55 +00:00
28 changed files with 119 additions and 67 deletions
-1
View File
@@ -1950,7 +1950,6 @@
"repo.settings.webhook_deletion": "Odstranit webový háček",
"repo.settings.webhook_deletion_desc": "Odstranění webového háčku smaže jeho nastavení a historii doručení. Pokračovat?",
"repo.settings.webhook_deletion_success": "Webový háček byl smazán.",
"repo.settings.webhook.test_delivery_desc_disabled": "Chcete-li tento webový háček otestovat s falešnou událostí, aktivujte ho.",
"repo.settings.webhook.request": "Požadavek",
"repo.settings.webhook.response": "Odpověď",
"repo.settings.webhook.headers": "Hlavičky",
-1
View File
@@ -2251,7 +2251,6 @@
"repo.settings.webhook_deletion_success": "Webhook wurde entfernt.",
"repo.settings.webhook.test_delivery": "Test Push Ereignis",
"repo.settings.webhook.test_delivery_desc": "Teste diesen Webhook mit einem Fake-Push-Event.",
"repo.settings.webhook.test_delivery_desc_disabled": "Um diesen Webhook mit einem Fake-Event zu testen, aktiviere ihn.",
"repo.settings.webhook.request": "Anfrage",
"repo.settings.webhook.response": "Antwort",
"repo.settings.webhook.headers": "Kopfzeilen",
-1
View File
@@ -1781,7 +1781,6 @@
"repo.settings.webhook_deletion": "Αφαίρεση Webhook",
"repo.settings.webhook_deletion_desc": "Η αφαίρεση ενός webhook διαγράφει τις ρυθμίσεις και το ιστορικό παραδόσεων. Συνέχεια;",
"repo.settings.webhook_deletion_success": "Το webhook έχει αφαιρεθεί.",
"repo.settings.webhook.test_delivery_desc_disabled": "Για να δοκιμάσετε αυτό το webhook με μια ψεύτικη κλήση, ενεργοποιήστε το.",
"repo.settings.webhook.request": "Αίτημα",
"repo.settings.webhook.response": "Απάντηση",
"repo.settings.webhook.headers": "Κεφαλίδες",
-1
View File
@@ -2251,7 +2251,6 @@
"repo.settings.webhook_deletion_success": "The webhook has been removed.",
"repo.settings.webhook.test_delivery": "Test Push Event",
"repo.settings.webhook.test_delivery_desc": "Test this webhook with a fake push event.",
"repo.settings.webhook.test_delivery_desc_disabled": "To test this webhook with a fake event, activate it.",
"repo.settings.webhook.request": "Request",
"repo.settings.webhook.response": "Response",
"repo.settings.webhook.headers": "Headers",
-1
View File
@@ -1753,7 +1753,6 @@
"repo.settings.webhook_deletion": "Eliminar Webhook",
"repo.settings.webhook_deletion_desc": "Eliminar un webhook borra sus ajustes e historial de entrega. ¿Continuar?",
"repo.settings.webhook_deletion_success": "El webhook ha sido eliminado.",
"repo.settings.webhook.test_delivery_desc_disabled": "Para probar este webhook con un evento falso, actívalo.",
"repo.settings.webhook.request": "Petición",
"repo.settings.webhook.response": "Respuesta",
"repo.settings.webhook.headers": "Encabezado",
-1
View File
@@ -2251,7 +2251,6 @@
"repo.settings.webhook_deletion_success": "Le webhook a été supprimé.",
"repo.settings.webhook.test_delivery": "Tester lenvoi",
"repo.settings.webhook.test_delivery_desc": "Testez ce webhook avec un faux événement.",
"repo.settings.webhook.test_delivery_desc_disabled": "Pour tester ce webhook avec un faux événement, activez-le.",
"repo.settings.webhook.request": "Requête",
"repo.settings.webhook.response": "Réponse",
"repo.settings.webhook.headers": "Entêtes",
-1
View File
@@ -2251,7 +2251,6 @@
"repo.settings.webhook_deletion_success": "Tá an Crúca Gréasán bainte amach.",
"repo.settings.webhook.test_delivery": "Imeacht Brúigh Tástála",
"repo.settings.webhook.test_delivery_desc": "Déan tástáil ar an webhook seo le teagmhas brú bréige.",
"repo.settings.webhook.test_delivery_desc_disabled": "Chun an Crúca Gréasán seo a thástáil le himeacht bhréige, gníomhachtaigh é.",
"repo.settings.webhook.request": "Iarratas",
"repo.settings.webhook.response": "Freagra",
"repo.settings.webhook.headers": "Ceanntásca",
-1
View File
@@ -2251,7 +2251,6 @@
"repo.settings.webhook_deletion_success": "Webhookを削除しました。",
"repo.settings.webhook.test_delivery": "プッシュ・イベントによるテスト",
"repo.settings.webhook.test_delivery_desc": "ダミーのプッシュ・イベントでこのWebhookをテストします。",
"repo.settings.webhook.test_delivery_desc_disabled": "このWebhookをダミーのイベントでテストするには、有効にしてください。",
"repo.settings.webhook.request": "リクエスト",
"repo.settings.webhook.response": "レスポンス",
"repo.settings.webhook.headers": "ヘッダー",
-1
View File
@@ -2248,7 +2248,6 @@
"repo.settings.webhook_deletion_success": "Webhook을 삭제했습니다.",
"repo.settings.webhook.test_delivery": "푸시 이벤트 테스트",
"repo.settings.webhook.test_delivery_desc": "가짜 푸시 이벤트로 웹훅을 테스트합니다.",
"repo.settings.webhook.test_delivery_desc_disabled": "가짜 이벤트로 이 웹훅을 테스트하려면 활성화하십시오.",
"repo.settings.webhook.request": "요청",
"repo.settings.webhook.response": "응답",
"repo.settings.webhook.headers": "제목",
-1
View File
@@ -1812,7 +1812,6 @@
"repo.settings.webhook_deletion": "Noņemt tīmekļa āķi",
"repo.settings.webhook_deletion_desc": "Noņemot tīmekļa āķi, tiks dzēsti visi tā iestatījumi un piegādes vēsture. Vai turpināt?",
"repo.settings.webhook_deletion_success": "Tīmekļa āķis tika noņemts.",
"repo.settings.webhook.test_delivery_desc_disabled": "Lai pārbaudītu šo tīmekļa āķi ar neīstu notikumu, tas ir jāiespējo.",
"repo.settings.webhook.request": "Pieprasījums",
"repo.settings.webhook.response": "Atbilde",
"repo.settings.webhook.headers": "Galvenes",
-1
View File
@@ -2019,7 +2019,6 @@
"repo.settings.webhook_deletion_success": "O webhook foi removido.",
"repo.settings.webhook.test_delivery": "Testar Evento de Push",
"repo.settings.webhook.test_delivery_desc": "Teste este webhook com um evento falso.",
"repo.settings.webhook.test_delivery_desc_disabled": "Para testar este webhook com um evento falso, ative-o.",
"repo.settings.webhook.request": "Solicitação",
"repo.settings.webhook.response": "Resposta",
"repo.settings.webhook.headers": "Cabeçalhos",
-1
View File
@@ -2251,7 +2251,6 @@
"repo.settings.webhook_deletion_success": "O automatismo web foi removido.",
"repo.settings.webhook.test_delivery": "Testar o envio",
"repo.settings.webhook.test_delivery_desc": "Testar este automatismo web com um evento de envio falso.",
"repo.settings.webhook.test_delivery_desc_disabled": "Para testar este automatismo web com um evento falso, habilite-o.",
"repo.settings.webhook.request": "Pedido",
"repo.settings.webhook.response": "Resposta",
"repo.settings.webhook.headers": "Cabeçalhos",
-1
View File
@@ -2204,7 +2204,6 @@
"repo.settings.webhook_deletion_success": "Web isteği silindi.",
"repo.settings.webhook.test_delivery": "İtme Olayını Sına",
"repo.settings.webhook.test_delivery_desc": "Bu web istemcisini sahte bir itme olayıyla sınayın.",
"repo.settings.webhook.test_delivery_desc_disabled": "Bu web istemcisini sahte bir olayla denemek için etkinleştirin.",
"repo.settings.webhook.request": "İstekler",
"repo.settings.webhook.response": "Cevaplar",
"repo.settings.webhook.headers": "Başlıklar",
-1
View File
@@ -2251,7 +2251,6 @@
"repo.settings.webhook_deletion_success": "Web 钩子删除成功!",
"repo.settings.webhook.test_delivery": "测试推送事件",
"repo.settings.webhook.test_delivery_desc": "用假推送事件测试这个 Web 钩子。",
"repo.settings.webhook.test_delivery_desc_disabled": "要用假事件测试这个 Web钩子,请激活它。",
"repo.settings.webhook.request": "请求内容",
"repo.settings.webhook.response": "响应内容",
"repo.settings.webhook.headers": "头信息",
-1
View File
@@ -1952,7 +1952,6 @@
"repo.settings.webhook_deletion": "移除 Webhook",
"repo.settings.webhook_deletion_desc": "移除 Webhook 將刪除它的設定及傳送記錄,是否繼續?",
"repo.settings.webhook_deletion_success": "Webhook 已移除。",
"repo.settings.webhook.test_delivery_desc_disabled": "要使用假事件測試此 Webhook,請啟用它。",
"repo.settings.webhook.request": "請求",
"repo.settings.webhook.response": "回應",
"repo.settings.webhook.headers": "標頭",
+1 -1
View File
@@ -177,7 +177,7 @@ func TestHook(ctx *context.APIContext) {
commit := convert.ToPayloadCommit(ctx, ctx.Repo.Repository, ctx.Repo.Commit)
commitID := ctx.Repo.Commit.ID.String()
if err := webhook_service.PrepareWebhook(ctx, hook, webhook_module.HookEventPush, &api.PushPayload{
if err := webhook_service.PrepareTestWebhook(ctx, hook, webhook_module.HookEventPush, &api.PushPayload{
Ref: ref,
Before: commitID,
After: commitID,
+1
View File
@@ -56,6 +56,7 @@ func initTestQueueOnce() {
for {
select {
case <-ctx.Done():
return
case <-time.After(500 * time.Millisecond):
if adding {
if testQueue.GetQueueItemNumber() == qs.Length {
+11 -16
View File
@@ -664,19 +664,14 @@ func TestWebhook(ctx *context.Context) {
return
}
// Grab latest commit or fake one if it's empty repository.
// Note: in old code, the "ctx.Repo.Commit" is the last commit of the default branch.
// New code doesn't set that commit, so it always uses the fake commit to test webhook.
commit := ctx.Repo.Commit
if commit == nil {
ghost := user_model.NewGhostUser()
objectFormat := git.ObjectFormatFromName(ctx.Repo.Repository.ObjectFormatName)
commit = &git.Commit{
ID: objectFormat.EmptyObjectID(),
Author: ghost.NewGitSig(),
Committer: ghost.NewGitSig(),
CommitMessage: git.CommitMessage{MessageRaw: "This is a fake commit"},
}
// use a fake commit to test webhook
ghostUser := user_model.NewGhostUser()
objectFormat := git.ObjectFormatFromName(ctx.Repo.Repository.ObjectFormatName)
commit := &git.Commit{
ID: objectFormat.EmptyObjectID(),
Author: ghostUser.NewGitSig(),
Committer: ghostUser.NewGitSig(),
CommitMessage: git.CommitMessage{MessageRaw: "This is a fake commit for webhook push test"},
}
apiUser := convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone)
@@ -697,7 +692,7 @@ func TestWebhook(ctx *context.Context) {
commitID := commit.ID.String()
p := &api.PushPayload{
Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch,
Ref: git.RefNameFromBranch(ctx.Repo.Repository.DefaultBranch).String(),
Before: commitID,
After: commitID,
CompareURL: setting.AppURL + ctx.Repo.Repository.ComposeCompareURL(commitID, commitID),
@@ -708,8 +703,8 @@ func TestWebhook(ctx *context.Context) {
Pusher: apiUser,
Sender: apiUser,
}
if err := webhook_service.PrepareWebhook(ctx, w, webhook_module.HookEventPush, p); err != nil {
ctx.Flash.Error("PrepareWebhook: " + err.Error())
if err := webhook_service.PrepareTestWebhook(ctx, w, webhook_module.HookEventPush, p); err != nil {
ctx.Flash.Error("PrepareTestWebhook: " + err.Error())
ctx.Status(http.StatusInternalServerError)
} else {
ctx.Flash.Info(ctx.Tr("repo.settings.webhook.delivery.success"))
+9 -7
View File
@@ -373,16 +373,18 @@ func RunnerBulkActionPost(ctx *context.Context) {
return
}
var runnerIDs []int64
if rCtx.IsAdmin {
// ATTENTION: it completely depends on the assumption that the doer is "site admin"
// So it doesn't do extra permission check to the runner IDs
// In the future, if you need to support such operation on non-admin pages, be careful!
runnerIDs = ctx.FormStringInt64s("ids")
} else {
if !rCtx.IsAdmin {
ctx.HTTPError(http.StatusForbidden, "bulk actions are admin-only")
return
}
// ATTENTION: it completely depends on the assumption that the doer is "site admin"
// So it doesn't do extra permission check to the runner IDs
// In the future, if you need to support such operation on non-admin pages, be careful!
runnerIDs := ctx.FormStringInt64s("ids")
if len(runnerIDs) == 0 {
ctx.HTTPError(http.StatusBadRequest, "missing runner IDs")
return
}
action := ctx.FormString("action")
var successKey, failedKey string
+27
View File
@@ -129,6 +129,33 @@ func checkBranchFilter(branchFilter string, ref git.RefName) bool {
return g.Match(ref.String())
}
// PrepareTestWebhook always creates and enqueues a hook task for manual testing.
// Unlike PrepareWebhook, it ignores event subscriptions and branch filters so the
// Test Push Event control can verify delivery even when those gates would suppress
// a real event.
func PrepareTestWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook_module.HookEventType, p api.Payloader) error {
if setting.DisableWebhooks {
return nil
}
payload, err := p.JSONPayload()
if err != nil {
return fmt.Errorf("JSONPayload for %s: %w", event, err)
}
task, err := webhook_model.CreateHookTask(ctx, &webhook_model.HookTask{
HookID: w.ID,
PayloadContent: string(payload),
EventType: event,
PayloadVersion: 2,
})
if err != nil {
return fmt.Errorf("CreateHookTask for %s: %w", event, err)
}
return enqueueHookTask(task.ID)
}
// PrepareWebhook creates a hook task and enqueues it for processing.
// The payload is saved as-is. The adjustments depending on the webhook type happen
// right before delivery, in the [Deliver] method.
+35
View File
@@ -30,6 +30,7 @@ func TestWebhookService(t *testing.T) {
t.Run("PrepareBranchFilterNoMatch", testWebhookPrepareBranchFilterNoMatch)
t.Run("WebhookUserMail", testWebhookUserMail)
t.Run("CheckBranchFilter", testWebhookCheckBranchFilter)
t.Run("PrepareTestWebhookIgnoresGates", testPrepareTestWebhookIgnoresGates)
}
func testWebhookGetSlackHook(t *testing.T) {
@@ -132,3 +133,37 @@ func testWebhookCheckBranchFilter(t *testing.T) {
assert.Equal(t, v.match, checkBranchFilter(v.filter, v.ref), "filter: %q ref: %q", v.filter, v.ref)
}
}
func testPrepareTestWebhookIgnoresGates(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
hook := &webhook_model.Webhook{
RepoID: repo.ID,
URL: "http://localhost/gitea-webhook-test-prepare_test_webhook",
ContentType: webhook_model.ContentTypeJSON,
IsActive: true,
HookEvent: &webhook_module.HookEvent{
ChooseEvents: true,
BranchFilter: "dev",
HookEvents: webhook_module.HookEvents{
webhook_module.HookEventWorkflowRun: true,
},
},
}
require.NoError(t, hook.UpdateEvent())
require.NoError(t, db.Insert(t.Context(), hook))
payload := &api.PushPayload{
Ref: "refs/heads/master",
Commits: []*api.PayloadCommit{{}},
}
hookTask := &webhook_model.HookTask{HookID: hook.ID, EventType: webhook_module.HookEventPush}
// Real deliveries stay gated: no push event + branch filter mismatch => nothing queued.
unittest.AssertNotExistsBean(t, hookTask)
require.NoError(t, PrepareWebhook(t.Context(), hook, webhook_module.HookEventPush, payload))
unittest.AssertNotExistsBean(t, hookTask)
// Manual test delivery always queues so the endpoint can be verified.
require.NoError(t, PrepareTestWebhook(t.Context(), hook, webhook_module.HookEventPush, payload))
unittest.AssertExistsAndLoadBean(t, hookTask)
}
+13 -3
View File
@@ -1,7 +1,17 @@
{{template "devtest/devtest-header"}}
<div class="page-content devtest">
<div class="ui container">
<h3>Flex List (standalone)</h3>
<h3>Flex Relaxed List</h3>
<div class="flex-container tw-border">
<div class="flex-relaxed-list tw-flex-1">
<div class="flex-left-right">
<span class="gt-ellipsis">left looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong</span>
<span>right</span>
</div>
</div>
</div>
<h3>Flex Divided List (standalone)</h3>
<div class="divider"></div>
<div class="flex-divided-list items-with-main">
<div class="item">
@@ -87,7 +97,7 @@
<div class="divider"></div>
<h3>Flex List (with "ui segment")</h3>
<h3>Flex Divided List (with "ui segment")</h3>
<div class="ui attached segment">
<div class="flex-divided-list">
<div class="item">item 1</div>
@@ -101,7 +111,7 @@
<div class="item">item 2</div>
</div>
</div>
<h3>Flex List (with "ui segment fitted", items have their own padding)</h3>
<h3>Flex Divided List (with "ui segment fitted", items have their own padding)</h3>
<div class="ui fitted segment">
<div class="flex-divided-list items-px-default">
<div class="item">item 1</div>
+2 -2
View File
@@ -1,6 +1,6 @@
<div class="ui container tw-flex tw-gap-4">
<div class="ui container flex-container">
<div>{{ctx.AvatarUtils.Avatar .Org 100}}</div>
<div class="flex-relaxed-list">
<div class="flex-relaxed-list tw-flex-1">
<div class="ui header flex-left-right tw-m-0">
<div class="flex-text-block">
<span class="tw-text-2xl">{{.Org.DisplayName}}</span>
+7 -11
View File
@@ -1,16 +1,12 @@
{{$isNew:=or .PageIsSettingsHooksNew .PageIsAdminDefaultHooksNew .PageIsAdminSystemHooksNew}}
{{if .PageIsSettingsHooksEdit}}
<h4 class="ui top attached header">
{{ctx.Locale.Tr "repo.settings.recent_deliveries"}}
<h4 class="ui top attached header flex-left-right">
<span>{{ctx.Locale.Tr "repo.settings.recent_deliveries"}}</span>
{{if .Permission.IsAdmin}}
<div class="ui right">
<!-- the button is wrapped with a span because the tooltip doesn't show on hover if we put data-tooltip-content directly on the button -->
<span data-tooltip-content="{{if or $isNew .Webhook.IsActive}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc"}}{{else}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc_disabled"}}{{end}}">
<button class="ui tiny button{{if not (or $isNew .Webhook.IsActive)}} disabled{{end}}" id="test-delivery" data-link="{{.Link}}/test">
<span class="text">{{ctx.Locale.Tr "repo.settings.webhook.test_delivery"}}</span>
</button>
</span>
</div>
<button class="ui tiny button" id="test-delivery" data-link="{{.Link}}/test"
data-tooltip-content="{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc"}}"
>
{{ctx.Locale.Tr "repo.settings.webhook.test_delivery"}}
</button>
{{end}}
</h4>
<div class="ui attached segment">
+3 -3
View File
@@ -44,9 +44,9 @@
<div class="ui attached segment tw-hidden" data-global-init="initRunnerBulkToolbar">
<form action="{{$.Link}}/bulk" method="post" class="form-fetch-action">
<input type="hidden" name="ids">
<button class="ui small button" name="action" value="disable">{{ctx.Locale.Tr "actions.runners.disable_runner"}} <span class="runner-bulk-count"></span></button>
<button class="ui small button" name="action" value="enable">{{ctx.Locale.Tr "actions.runners.enable_runner"}} <span class="runner-bulk-count"></span></button>
<button class="ui small red button" name="action" value="delete"
<button class="ui small button runner-bulk-action" name="action" value="disable">{{ctx.Locale.Tr "actions.runners.disable_runner"}} <span class="runner-bulk-count"></span></button>
<button class="ui small button runner-bulk-action" name="action" value="enable">{{ctx.Locale.Tr "actions.runners.enable_runner"}} <span class="runner-bulk-count"></span></button>
<button class="ui small red button runner-bulk-action" name="action" value="delete"
data-modal-confirm-header="{{ctx.Locale.Tr "actions.runners.delete_runner_header"}}"
data-modal-confirm-content="{{ctx.Locale.Tr "actions.runners.delete_runner_notice"}}"
>{{ctx.Locale.Tr "actions.runners.delete_runner"}} <span class="runner-bulk-count"></span>
@@ -196,6 +196,13 @@ func TestActionsRunnerModify(t *testing.T) {
doBulk(t, sessionAdmin, "evict", allIDs, http.StatusBadRequest)
})
t.Run("EmptyIDs", func(t *testing.T) {
doBulk(t, sessionAdmin, "delete", nil, http.StatusBadRequest)
for _, id := range allIDs {
unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: id})
}
})
t.Run("DisableEnable", func(t *testing.T) {
doBulk(t, sessionAdmin, "disable", allIDs, http.StatusOK)
for _, id := range allIDs {
+2
View File
@@ -3,6 +3,8 @@
display: flex;
flex-direction: column;
gap: var(--gap-block);
min-width: 0; /* keep the same style as "flex-text-block" etc, make the text content wrap/ellipse correctly */
max-width: 100%;
}
.flex-relaxed-list > .divider {
+1 -9
View File
@@ -36,6 +36,7 @@ function initAdminRunnerBulk(toolbar: HTMLElement) {
const refresh = () => {
const checked = Array.from(rowCheckboxes).filter((c) => c.checked);
formRunnerIds.value = checked.map((c) => c.getAttribute('data-runner-id')!).join(',');
toggleElem(toolbar, checked.length > 0);
for (const btn of actionButtons) {
btn.querySelector<HTMLElement>('.runner-bulk-count')!.textContent = `(${checked.length})`;
@@ -50,15 +51,6 @@ function initAdminRunnerBulk(toolbar: HTMLElement) {
});
for (const cb of rowCheckboxes) cb.addEventListener('change', refresh);
refresh();
const collectSelectedIds = () => {
const ids = [];
for (const cb of rowCheckboxes) {
if (cb.checked) ids.push(cb.getAttribute('data-runner-id')!);
}
return ids.join(',');
};
formRunnerIds.value = collectSelectedIds();
}
function initAdminUser() {