mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-25 10:11:52 +00:00
fix: abort superseded issue suggestion requests (#38620)
Fix regression from https://github.com/go-gitea/gitea/pull/38610 `perfect-debounce` allowed only one request in flight; `debounce` does not, so a slow older request can resolve after a newer one and leave a stale suggestion menu. Superseded requests are now aborted.
This commit is contained in:
@@ -4,11 +4,12 @@ import {svg} from '../../svg.ts';
|
||||
import {parseIssueHref, parseRepoOwnerPathInfo} from '../../utils.ts';
|
||||
import {createElementFromAttrs, createElementFromHTML} from '../../utils/dom.ts';
|
||||
import {getIssueColorClass, getIssueIcon} from '../issue.ts';
|
||||
import {errorName} from '../../modules/errors.ts';
|
||||
import {debounce} from '../../utils/func.ts';
|
||||
import type TextExpanderElement from '@github/text-expander-element';
|
||||
import type {TextExpanderChangeEvent, TextExpanderResult} from '@github/text-expander-element';
|
||||
|
||||
async function fetchIssueSuggestions(key: string, text: string): Promise<TextExpanderResult> {
|
||||
async function fetchIssueSuggestions(key: string, text: string, signal: AbortSignal): Promise<TextExpanderResult> {
|
||||
const issuePathInfo = parseIssueHref(window.location.href);
|
||||
if (!issuePathInfo.ownerName) {
|
||||
const repoOwnerPathInfo = parseRepoOwnerPathInfo(window.location.pathname);
|
||||
@@ -18,7 +19,7 @@ async function fetchIssueSuggestions(key: string, text: string): Promise<TextExp
|
||||
}
|
||||
if (!issuePathInfo.ownerName) return {matched: false};
|
||||
|
||||
const matches = await matchIssue(issuePathInfo.ownerName, issuePathInfo.repoName, issuePathInfo.indexString, text);
|
||||
const matches = await matchIssue(issuePathInfo.ownerName, issuePathInfo.repoName, issuePathInfo.indexString, text, signal);
|
||||
if (!matches.length) return {matched: false};
|
||||
|
||||
const ul = createElementFromAttrs('ul', {class: 'suggestions'});
|
||||
@@ -48,6 +49,7 @@ export function initTextExpander(expander: TextExpanderElement) {
|
||||
return keyStart > lineStart;
|
||||
};
|
||||
|
||||
let suggestionsController = new AbortController();
|
||||
const debouncedIssueSuggestions = debounce(async (key: string, text: string): Promise<TextExpanderResult> => {
|
||||
// https://github.com/github/text-expander-element/issues/71
|
||||
// Upstream bug: when using "multiword+promise", TextExpander will get wrong "key" position.
|
||||
@@ -58,10 +60,17 @@ export function initTextExpander(expander: TextExpanderElement) {
|
||||
// check the input before the request, to avoid emitting empty query to backend (still related to the upstream bug)
|
||||
if (!shouldShowIssueSuggestions()) return {matched: false};
|
||||
// await sleep(Math.random() * 1000); // help to reproduce the text-expander bug
|
||||
const ret = await fetchIssueSuggestions(key, text);
|
||||
// check the input again to avoid text-expander using incorrect position (upstream bug)
|
||||
if (!shouldShowIssueSuggestions()) return {matched: false};
|
||||
return ret;
|
||||
suggestionsController.abort(); // only the newest request may answer
|
||||
suggestionsController = new AbortController();
|
||||
try {
|
||||
const ret = await fetchIssueSuggestions(key, text, suggestionsController.signal);
|
||||
// check the input again to avoid text-expander using incorrect position (upstream bug)
|
||||
if (!shouldShowIssueSuggestions()) return {matched: false};
|
||||
return ret;
|
||||
} catch (err) {
|
||||
if (errorName(err) !== 'AbortError') throw err;
|
||||
return {matched: false};
|
||||
}
|
||||
}, 300); // to match onInputDebounce delay
|
||||
|
||||
expander.addEventListener('text-expander-change', (e: TextExpanderChangeEvent) => {
|
||||
|
||||
@@ -71,8 +71,8 @@ export async function matchMention(mentionsUrl: string, queryText: string): Prom
|
||||
return sortAndReduce(results);
|
||||
}
|
||||
|
||||
export async function matchIssue(owner: string, repo: string, issueIndexStr: string, query: string): Promise<Issue[]> {
|
||||
const res = await GET(`${window.config.appSubUrl}/${owner}/${repo}/issues/suggestions?q=${encodeURIComponent(query)}`);
|
||||
export async function matchIssue(owner: string, repo: string, issueIndexStr: string, query: string, signal: AbortSignal): Promise<Issue[]> {
|
||||
const res = await GET(`${window.config.appSubUrl}/${owner}/${repo}/issues/suggestions?q=${encodeURIComponent(query)}`, {signal});
|
||||
|
||||
const issues: Issue[] = await res.json();
|
||||
const issueNumber = parseInt(issueIndexStr);
|
||||
|
||||
Reference in New Issue
Block a user