mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-26 23:56:37 +09:00
3875db1974
Adds a read-only Actions job queue: running jobs first, then waiting jobs in the order a runner picks them up. It is shown instance-wide in the admin Actions section with owner, repository and status filters, and per repository in the Actions tab. Both lists refresh in place. Pending work is currently only visible per repository and newest-first, so nothing shows what is queued, in which order, or what occupies the runners. Reordering the queue will be proposed separately. A migration adds indexes for the runner pickup query and repository-scoped status lookups. * Fix #34198 <img width="1345" height="451" alt="image" src="https://github.com/user-attachments/assets/7d52ff76-81b4-44e8-b583-d7d89c9dffcd" /> <img width="1809" height="1134" alt="image" src="https://github.com/user-attachments/assets/4d56c0cb-bae7-4ce2-8f3c-75163b2bc7f4" /> --------- Co-authored-by: Zettat123 <zettat123@gmail.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
103 lines
5.4 KiB
TypeScript
103 lines
5.4 KiB
TypeScript
import {
|
|
createElementFromAttrs, createElementFromHTML,
|
|
queryElemChildren, querySingleVisibleElem,
|
|
protectMorphElements, recoverMorphElements,
|
|
toggleElem, morphElementWithProtection,
|
|
} from './dom.ts';
|
|
|
|
test('createElementFromHTML', () => {
|
|
expect(createElementFromHTML('<a>foo<span>bar</span></a>').outerHTML).toEqual('<a>foo<span>bar</span></a>');
|
|
expect(createElementFromHTML('<tr data-x="1"><td>foo</td></tr>').outerHTML).toEqual('<tr data-x="1"><td>foo</td></tr>');
|
|
expect(createElementFromHTML('<TR data-x="1"><td>foo</td></TR>').outerHTML).toEqual('<tr data-x="1"><td>foo</td></tr>');
|
|
expect(createElementFromHTML('<trx></trx>').outerHTML).toEqual('<trx></trx>');
|
|
});
|
|
|
|
test('createElementFromAttrs', () => {
|
|
const el = createElementFromAttrs('button', {
|
|
id: 'the-id',
|
|
class: 'cls-1 cls-2',
|
|
disabled: true,
|
|
checked: false,
|
|
required: null,
|
|
tabindex: 0,
|
|
'data-foo': 'the-data',
|
|
}, 'txt', createElementFromHTML('<span>inner</span>'));
|
|
expect(el.outerHTML).toEqual('<button id="the-id" class="cls-1 cls-2" disabled="" tabindex="0" data-foo="the-data">txt<span>inner</span></button>');
|
|
});
|
|
|
|
test('querySingleVisibleElem', () => {
|
|
const el = document.createElement('div');
|
|
document.body.append(el); // layout, and thus visibility, is only computed in the document
|
|
expect(querySingleVisibleElem(el, 'span')).toBeNull();
|
|
el.innerHTML = '<span>foo</span>';
|
|
expect(querySingleVisibleElem(el, 'span')!.textContent).toEqual('foo');
|
|
el.innerHTML = '<span style="display: none;">foo</span><span>bar</span>';
|
|
expect(querySingleVisibleElem(el, 'span')!.textContent).toEqual('bar');
|
|
el.innerHTML = '<span class="some-class tw-hidden">foo</span><span>bar</span>';
|
|
expect(querySingleVisibleElem(el, 'span')!.textContent).toEqual('bar');
|
|
el.innerHTML = '<span>foo</span><span>bar</span>';
|
|
expect(() => querySingleVisibleElem(el, 'span')).toThrow('Expected exactly one visible element');
|
|
});
|
|
|
|
test('queryElemChildren', () => {
|
|
const el = createElementFromHTML('<div><span class="a">a</span><span class="b">b</span></div>');
|
|
const children = queryElemChildren(el, '.a');
|
|
expect(children.length).toEqual(1);
|
|
});
|
|
|
|
test('toggleElem', () => {
|
|
const el = createElementFromHTML('<div><div>a</div><div class="tw-hidden">b</div></div>');
|
|
toggleElem(el.children);
|
|
expect(el.outerHTML).toEqual('<div><div class="tw-hidden">a</div><div class="">b</div></div>');
|
|
toggleElem(el.children, false);
|
|
expect(el.outerHTML).toEqual('<div><div class="tw-hidden">a</div><div class="tw-hidden">b</div></div>');
|
|
toggleElem(el.children, true);
|
|
expect(el.outerHTML).toEqual('<div><div class="">a</div><div class="">b</div></div>');
|
|
});
|
|
|
|
test('protectMorphElements', () => {
|
|
const el = createElementFromHTML('<div><span data-morph-protect="">foo</span></div>');
|
|
const protectedElems = protectMorphElements(el);
|
|
|
|
const span = el.querySelector('span')!;
|
|
const spanMorphProtectId = span.getAttribute('data-morph-protect');
|
|
expect(spanMorphProtectId).toBeTruthy();
|
|
expect(el.outerHTML).toEqual(`<div><span data-morph-protect="${spanMorphProtectId}">foo</span></div>`);
|
|
span.textContent = 'bar';
|
|
span.classList.add('new-class');
|
|
expect(el.outerHTML).toEqual(`<div><span data-morph-protect="${spanMorphProtectId}" class="new-class">bar</span></div>`);
|
|
|
|
recoverMorphElements(el, protectedElems);
|
|
expect(el.outerHTML).toEqual('<div><span data-morph-protect="">foo</span></div>');
|
|
});
|
|
|
|
describe('morphElementWithProtection', () => {
|
|
const newElHtml = '<div><div><span>new</span><div class="ui dropdown">changed</div></div></div>';
|
|
it('morph normal', () => {
|
|
const el = createElementFromHTML('<div><div><span>old</span><div class="ui dropdown active"></div></div></div>');
|
|
const newEl = createElementFromHTML(newElHtml);
|
|
morphElementWithProtection(el, newEl, {morphStyle: 'outerHTML'});
|
|
// span is changed, but dropdown is skipped because it is active
|
|
expect(el.outerHTML).toEqual('<div><div><span>new</span><div class="ui dropdown active"></div></div></div>');
|
|
});
|
|
it('morph whole', () => {
|
|
const el = createElementFromHTML('<div><div data-morph-whole><span>old</span><div class="ui dropdown active"></div></div></div>');
|
|
const newEl = createElementFromHTML(newElHtml);
|
|
morphElementWithProtection(el, newEl, {morphStyle: 'outerHTML'});
|
|
// span is not changed, because the parent div is marked as data-morph-whole and there is an active dropdown, so it is skipped
|
|
expect(el.outerHTML).toEqual('<div><div data-morph-whole=""><span>old</span><div class="ui dropdown active"></div></div></div>');
|
|
});
|
|
it('morph protection', () => {
|
|
const el = createElementFromHTML('<div><span></span><div class="ui dropdown"></div></div>');
|
|
const newEl = createElementFromHTML('<div><span>new</span><div class="ui dropdown">changed</div></div>');
|
|
const elSpanOld = el.querySelector('span');
|
|
const elDropdownOld = el.querySelector('.ui.dropdown');
|
|
const morphedEl = morphElementWithProtection(el, newEl, {morphStyle: 'outerHTML'});
|
|
expect(el.outerHTML).toEqual('<div><span>new</span><div class="ui dropdown">changed</div></div>');
|
|
const elSpanNew = morphedEl.querySelector('span');
|
|
const elDropdownNew = morphedEl.querySelector('.ui.dropdown');
|
|
expect(elSpanNew).toBe(elSpanOld); // span is morphed in place, so it is the same element
|
|
expect(elDropdownNew).not.toBe(elDropdownOld); // dropdown is protected and fully replaced, so it is a new element
|
|
});
|
|
});
|