Files
gitea/web_src/js/features/repo-issue-pull.ts
silverwind 0ec66b5380 Migrate from webpack to vite (#37002)
Replace webpack with Vite 8 as the frontend bundler. Frontend build is
around 3-4 times faster than before. Will work on all platforms
including riscv64 (via wasm).

`iife.js` is a classic render-blocking script in `<head>` (handles web
components/early DOM setup). `index.js` is loaded as a `type="module"`
script in the footer. All other JS chunks are also module scripts
(supported in all browsers since 2018).

Entry filenames are content-hashed (e.g. `index.C6Z2MRVQ.js`) and
resolved at runtime via the Vite manifest, eliminating the `?v=` cache
busting (which was unreliable in some scenarios like vscode dev build).

Replaces: https://github.com/go-gitea/gitea/pull/36896
Fixes: https://github.com/go-gitea/gitea/issues/17793
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-03-29 10:24:30 +00:00

134 lines
4.5 KiB
TypeScript

import {createApp} from 'vue';
import {GET, POST} from '../modules/fetch.ts';
import {fomanticQuery} from '../modules/fomantic/base.ts';
import {createElementFromHTML} from '../utils/dom.ts';
function initRepoPullRequestUpdate(el: HTMLElement) {
const prUpdateButtonContainer = el.querySelector('#update-pr-branch-with-base');
if (!prUpdateButtonContainer) return;
const prUpdateButton = prUpdateButtonContainer.querySelector<HTMLButtonElement>(':scope > button')!;
const prUpdateDropdown = prUpdateButtonContainer.querySelector(':scope > .ui.dropdown')!;
prUpdateButton.addEventListener('click', async function (e) {
e.preventDefault();
const redirect = this.getAttribute('data-redirect');
this.classList.add('is-loading');
let response: Response | undefined;
try {
response = await POST(this.getAttribute('data-do')!);
} catch (error) {
console.error(error);
} finally {
this.classList.remove('is-loading');
}
let data: Record<string, any> | undefined;
try {
data = await response?.json(); // the response is probably not a JSON
} catch (error) {
console.error(error);
}
if (data?.redirect) {
window.location.href = data.redirect;
} else if (redirect) {
window.location.href = redirect;
} else {
window.location.reload();
}
});
fomanticQuery(prUpdateDropdown).dropdown({
onChange(_text: string, _value: string, $choice: any) {
const choiceEl = $choice[0];
const url = choiceEl.getAttribute('data-do');
if (url) {
const buttonText = prUpdateButton.querySelector('.button-text');
if (buttonText) {
buttonText.textContent = choiceEl.textContent;
}
prUpdateButton.setAttribute('data-do', url);
}
},
});
}
function initRepoPullRequestCommitStatus(el: HTMLElement) {
for (const btn of el.querySelectorAll('.commit-status-hide-checks')) {
const panel = btn.closest('.commit-status-panel')!;
const list = panel.querySelector<HTMLElement>('.commit-status-list')!;
btn.addEventListener('click', () => {
list.style.maxHeight = list.style.maxHeight ? '' : '0px'; // toggle
btn.textContent = btn.getAttribute(list.style.maxHeight ? 'data-show-all' : 'data-hide-all');
});
}
}
async function initRepoPullRequestMergeForm(box: HTMLElement) {
const el = box.querySelector('#pull-request-merge-form');
if (!el) return;
const {default: PullRequestMergeForm} = await import('../components/PullRequestMergeForm.vue');
const view = createApp(PullRequestMergeForm);
view.mount(el);
}
function executeScripts(elem: HTMLElement) {
for (const oldScript of elem.querySelectorAll('script')) {
// TODO: that's the only way to load the data for the merge form. In the future
// we need to completely decouple the page data and embedded script
// eslint-disable-next-line github/no-dynamic-script-tag
const newScript = document.createElement('script');
for (const attr of oldScript.attributes) {
if (attr.name === 'type' && attr.value === 'module') continue;
newScript.setAttribute(attr.name, attr.value);
}
newScript.text = oldScript.text;
document.body.append(newScript);
}
}
export function initRepoPullMergeBox(el: HTMLElement) {
initRepoPullRequestCommitStatus(el);
initRepoPullRequestUpdate(el);
initRepoPullRequestMergeForm(el);
const reloadingIntervalValue = el.getAttribute('data-pull-merge-box-reloading-interval');
if (!reloadingIntervalValue) return;
const reloadingInterval = parseInt(reloadingIntervalValue);
const pullLink = el.getAttribute('data-pull-link');
let timerId: number | null;
let reloadMergeBox: () => Promise<void>;
const stopReloading = () => {
if (!timerId) return;
clearTimeout(timerId);
timerId = null;
};
const startReloading = () => {
if (timerId) return;
setTimeout(reloadMergeBox, reloadingInterval);
};
const onVisibilityChange = () => {
if (document.hidden) {
stopReloading();
} else {
startReloading();
}
};
reloadMergeBox = async () => {
const resp = await GET(`${pullLink}/merge_box`);
stopReloading();
if (!resp.ok) {
startReloading();
return;
}
document.removeEventListener('visibilitychange', onVisibilityChange);
const newElem = createElementFromHTML(await resp.text());
executeScripts(newElem);
el.replaceWith(newElem);
};
document.addEventListener('visibilitychange', onVisibilityChange);
startReloading();
}