mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-03 21:30:49 +00:00
enhance(webhook): add select all and deselect all buttons for custom events (#35980)
Adds `Select All` and `Deselect All` buttons to the custom events section of the webhook form. This is useful when you need all events but one. - The buttons toggle every event checkbox and keep the unsaved-changes prompt working - Fix the "Trigger On" radio spacing by removing a leftover Fomantic checkbox margin Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
<h4 class="ui top attached header flex-left-right">
|
||||
<span>{{ctx.Locale.Tr "repo.settings.recent_deliveries"}}</span>
|
||||
{{if .Permission.IsAdmin}}
|
||||
<button type="button" class="ui tiny button" id="test-delivery" data-link="{{.Link}}/test"
|
||||
<button type="button" class="ui tiny button" data-link="{{.Link}}/test" data-global-click="onWebhookTestDeliveryClick"
|
||||
data-tooltip-content="{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc"}}"
|
||||
>
|
||||
{{ctx.Locale.Tr "repo.settings.webhook.test_delivery"}}
|
||||
@@ -22,18 +22,18 @@
|
||||
{{else}}
|
||||
<span class="tw-text-red">{{svg "octicon-alert"}}</span>
|
||||
{{end}}
|
||||
<button type="button" class="btn interact-bg tw-p-2 toggle show-panel" data-panel="#info-{{.ID}}">{{.UUID}}</button>
|
||||
<button type="button" class="btn interact-bg tw-p-2 toggle show-panel" data-panel="#webhook-history-info-{{.ID}}">{{.UUID}}</button>
|
||||
</div>
|
||||
<span class="tw-text-text-light">
|
||||
{{DateUtils.TimeSince .Delivered}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="info tw-hidden tw-mt-2" id="info-{{.ID}}">
|
||||
<div class="info tw-hidden tw-mt-2" id="webhook-history-info-{{.ID}}">
|
||||
<div class="ui top attached tabular menu" data-global-init="initTabSwitcher">
|
||||
<a class="item active" data-tab="request-{{.ID}}">
|
||||
<a class="item active" data-tab="webhook-history-request-{{.ID}}">
|
||||
{{template "shared/misc/tabtitle" (ctx.Locale.Tr "repo.settings.webhook.request")}}
|
||||
</a>
|
||||
<a class="item" data-tab="response-{{.ID}}">
|
||||
<a class="item" data-tab="webhook-history-response-{{.ID}}">
|
||||
{{template "shared/misc/tabtitle" (ctx.Locale.Tr "repo.settings.webhook.response")}}
|
||||
{{if .ResponseInfo}}
|
||||
{{if .IsSucceed}}
|
||||
@@ -55,7 +55,7 @@
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="ui bottom attached tab segment active" data-tab="request-{{.ID}}">
|
||||
<div class="ui bottom attached tab segment active" data-tab="webhook-history-request-{{.ID}}">
|
||||
{{if .RequestInfo}}
|
||||
<h5>{{ctx.Locale.Tr "repo.settings.webhook.headers"}}</h5>
|
||||
<pre class="webhook-info"><strong>Request URL:</strong> {{.RequestInfo.URL}}
|
||||
@@ -68,13 +68,13 @@
|
||||
-
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="ui bottom attached tab segment" data-tab="response-{{.ID}}">
|
||||
<div class="ui bottom attached tab segment" data-tab="webhook-history-response-{{.ID}}">
|
||||
{{if .ResponseInfo}}
|
||||
<h5>{{ctx.Locale.Tr "repo.settings.webhook.headers"}}</h5>
|
||||
<pre class="webhook-info">{{range $key, $val := .ResponseInfo.Headers}}<strong>{{$key}}:</strong> {{$val}}
|
||||
{{end}}</pre>
|
||||
{{else}}(no response header){{end}}</pre>
|
||||
<h5>{{ctx.Locale.Tr "repo.settings.webhook.body"}}</h5>
|
||||
<pre class="webhook-info">{{.ResponseInfo.Body}}</pre>
|
||||
<pre class="webhook-info">{{or .ResponseInfo.Body "(no response body)"}}</pre>
|
||||
{{else}}
|
||||
-
|
||||
{{end}}
|
||||
|
||||
@@ -66,26 +66,30 @@
|
||||
<h4>{{ctx.Locale.Tr "repo.settings.event_desc"}}</h4>
|
||||
<div class="grouped event type fields">
|
||||
<div class="field">
|
||||
<div class="ui radio non-events checkbox">
|
||||
<div class="ui radio checkbox">
|
||||
<input name="events" type="radio" value="push_only" {{if or $isNew .Webhook.PushOnly}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.event_push_only"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio non-events checkbox">
|
||||
<div class="ui radio checkbox">
|
||||
<input name="events" type="radio" value="send_everything" {{if .Webhook.SendEverything}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.event_send_everything"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio events checkbox">
|
||||
<div class="ui radio checkbox">
|
||||
<input name="events" type="radio" value="choose_events" {{if .Webhook.ChooseEvents}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.event_choose"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="events fields ui grid {{if not .Webhook.ChooseEvents}}tw-hidden{{end}}">
|
||||
<div class="fields ui grid {{if not .Webhook.ChooseEvents}}tw-hidden{{end}} js-webhook-custom-events">
|
||||
<div class="fourteen wide column">
|
||||
<button type="button" class="ui tiny button" data-events-select-all="true">{{ctx.Locale.Tr "admin.notices.select_all"}}</button>
|
||||
<button type="button" class="ui tiny button" data-events-select-all="false">{{ctx.Locale.Tr "admin.notices.deselect_all"}}</button>
|
||||
</div>
|
||||
<!-- Repository Events -->
|
||||
<div class="fourteen wide column">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.event_header_repository"}}</label>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{{template "repo/settings/webhook/link_menu" ctx.RootData}}
|
||||
</div>
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<div class="ui attached segment" data-global-init="initCompWebHookEditorForm">
|
||||
{{template "repo/settings/webhook/gitea" ctx.RootData}}
|
||||
{{template "repo/settings/webhook/gogs" ctx.RootData}}
|
||||
{{template "repo/settings/webhook/slack" ctx.RootData}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {test, expect} from '@playwright/test';
|
||||
import {loginUser, apiCreateUser, randomString} from './utils.ts';
|
||||
import {login, loginUser, apiCreateUser, randomString} from './utils.ts';
|
||||
|
||||
test('update profile biography', async ({page, request}) => {
|
||||
const username = `e2e-settings-${randomString(8)}`;
|
||||
@@ -14,3 +14,13 @@ test('update profile biography', async ({page, request}) => {
|
||||
await page.getByRole('button', {name: 'Update Profile'}).click();
|
||||
await expect(page.getByLabel('Biography')).toHaveValue('');
|
||||
});
|
||||
|
||||
test('select and deselect all webhook events', async ({page}) => {
|
||||
await login(page);
|
||||
await page.goto('/user/settings/hooks/gitea/new');
|
||||
await page.getByRole('radio', {name: 'Custom Events'}).check();
|
||||
await page.getByRole('button', {name: 'Select All', exact: true}).click();
|
||||
await expect(page.getByRole('checkbox', {checked: false})).toHaveCount(0);
|
||||
await page.getByRole('button', {name: 'Deselect All', exact: true}).click();
|
||||
await expect(page.getByRole('checkbox', {checked: true})).toHaveAccessibleName('Active');
|
||||
});
|
||||
|
||||
@@ -88,10 +88,6 @@ input[type="checkbox"]:indeterminate::before {
|
||||
.ui.checkbox label {
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ui.checkbox label,
|
||||
.ui.radio.checkbox label {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
@@ -107,10 +103,6 @@ input[type="checkbox"]:indeterminate::before {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ui.radio.checkbox {
|
||||
min-height: var(--checkbox-size);
|
||||
}
|
||||
|
||||
/* "switch" styled checkbox */
|
||||
|
||||
.ui.toggle.checkbox {
|
||||
|
||||
@@ -114,10 +114,6 @@ textarea:focus,
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.ui.ui.form .field .fields .field:not(:only-child) .ui.checkbox {
|
||||
margin-top: 0.6em;
|
||||
}
|
||||
|
||||
.ui.form .field > .selection.dropdown {
|
||||
min-width: 14em; /* matches the default min width */
|
||||
width: 100%;
|
||||
@@ -255,9 +251,6 @@ textarea:focus,
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
.ui.form .fields > .field:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 767.98px) {
|
||||
.ui.form .fields {
|
||||
|
||||
@@ -952,16 +952,6 @@
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.repository.settings.webhook .events .column {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.repository.settings.webhook .events .help {
|
||||
font-size: 13px;
|
||||
margin-left: 26px;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.repository .repository-summary {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@@ -1,42 +1,46 @@
|
||||
import {registerGlobalEventFunc, registerGlobalInitFunc} from '../../modules/observer.ts';
|
||||
import {POST} from '../../modules/fetch.ts';
|
||||
import {hideElem, showElem, toggleElem} from '../../utils/dom.ts';
|
||||
import {queryElems, toggleElem} from '../../utils/dom.ts';
|
||||
|
||||
export function initCompWebHookEditor() {
|
||||
if (!document.querySelectorAll('.new.webhook').length) {
|
||||
return;
|
||||
}
|
||||
function initCompWebHookEditorForm(el: HTMLElement) {
|
||||
const elCustomEvents = el.querySelector('.js-webhook-custom-events')!;
|
||||
|
||||
for (const input of document.querySelectorAll<HTMLInputElement>('.events.checkbox input')) {
|
||||
input.addEventListener('change', function () {
|
||||
if (this.checked) {
|
||||
showElem('.events.fields');
|
||||
}
|
||||
// Trigger On: use custom events or not
|
||||
queryElems<HTMLInputElement>(el, 'input[name=events]', (input) => input.addEventListener('change', () => {
|
||||
if (!input.checked) return;
|
||||
toggleElem(elCustomEvents, input.value === 'choose_events');
|
||||
}));
|
||||
|
||||
// Select All / Deselect All custom events
|
||||
queryElems(el, 'button[data-events-select-all]', (btn) => btn.addEventListener('click', () => {
|
||||
const checked = btn.getAttribute('data-events-select-all') === 'true';
|
||||
queryElems<HTMLInputElement>(elCustomEvents, 'input[type=checkbox]', (input) => {
|
||||
input.checked = checked;
|
||||
input.dispatchEvent(new Event('change', {bubbles: true})); // for the areYouSure dirty tracking
|
||||
});
|
||||
}
|
||||
|
||||
for (const input of document.querySelectorAll<HTMLInputElement>('.non-events.checkbox input')) {
|
||||
input.addEventListener('change', function () {
|
||||
if (this.checked) {
|
||||
hideElem('.events.fields');
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
// some webhooks (like Gitea) allow to set the request method (GET/POST), and it would toggle the "Content Type" field
|
||||
const httpMethodInput = document.querySelector<HTMLInputElement>('#http_method');
|
||||
const httpMethodInput = el.querySelector<HTMLInputElement>('#http_method');
|
||||
if (httpMethodInput) {
|
||||
const updateContentType = function () {
|
||||
const updateContentType = () => {
|
||||
const visible = httpMethodInput.value === 'POST';
|
||||
toggleElem(document.querySelector('#content_type')!.closest('.field')!, visible);
|
||||
toggleElem(el.querySelector('#content_type')!.closest('.field')!, visible);
|
||||
};
|
||||
updateContentType();
|
||||
httpMethodInput.addEventListener('change', updateContentType);
|
||||
}
|
||||
}
|
||||
|
||||
// Test delivery
|
||||
document.querySelector<HTMLButtonElement>('#test-delivery')?.addEventListener('click', async function () {
|
||||
this.classList.add('is-loading', 'disabled');
|
||||
await POST(this.getAttribute('data-link')!);
|
||||
function initCompWebHookEditorHistory() {
|
||||
registerGlobalEventFunc('click', 'onWebhookTestDeliveryClick', async (el) => {
|
||||
el.classList.add('is-loading', 'disabled');
|
||||
await POST(el.getAttribute('data-link')!);
|
||||
setTimeout(() => window.location.reload(), 5000);
|
||||
});
|
||||
}
|
||||
|
||||
export function initCompWebHookEditor() {
|
||||
registerGlobalInitFunc('initCompWebHookEditorForm', initCompWebHookEditorForm);
|
||||
initCompWebHookEditorHistory();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user