Gitea treat JS errors seriously, so sometimes the JS errors caused by 3rdparty code (eg: browser extensions) would also be reported on Gitea UI: TypeError: WeakMap key undefined (caused by extension DarkReader's bug) #28861 To avoid fill the user's screen with a lot of error messages, this PR merges the same error messages into one, like this: ```js <div class="page-content"> <div class="... js-global-error" data-global-error-msg-compact="testmsg1" data-global-error-msg-count="2">test msg 1 (2)</div> <div class="... js-global-error" data-global-error-msg-compact="testmsg2" data-global-error-msg-count="1">test msg 2</div> </div> ```tags/v1.22.0-rc0
@@ -8,10 +8,21 @@ __webpack_public_path__ = `${window.config?.assetUrlPrefix ?? '/assets'}/`; | |||
export function showGlobalErrorMessage(msg) { | |||
const pageContent = document.querySelector('.page-content'); | |||
if (!pageContent) return; | |||
const el = document.createElement('div'); | |||
el.innerHTML = `<div class="ui container negative message center aligned js-global-error" style="white-space: pre-line;"></div>`; | |||
el.childNodes[0].textContent = msg; | |||
pageContent.prepend(el.childNodes[0]); | |||
// compact the message to a data attribute to avoid too many duplicated messages | |||
const msgCompact = msg.replace(/\W/g, '').trim(); | |||
let msgDiv = pageContent.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`); | |||
if (!msgDiv) { | |||
const el = document.createElement('div'); | |||
el.innerHTML = `<div class="ui container negative message center aligned js-global-error" style="white-space: pre-line;"></div>`; | |||
msgDiv = el.childNodes[0]; | |||
} | |||
// merge duplicated messages into "the message (count)" format | |||
const msgCount = Number(msgDiv.getAttribute(`data-global-error-msg-count`)) + 1; | |||
msgDiv.setAttribute(`data-global-error-msg-compact`, msgCompact); | |||
msgDiv.setAttribute(`data-global-error-msg-count`, msgCount.toString()); | |||
msgDiv.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); | |||
pageContent.prepend(msgDiv); | |||
} | |||
/** |
@@ -0,0 +1,12 @@ | |||
import {showGlobalErrorMessage} from './bootstrap.js'; | |||
test('showGlobalErrorMessage', () => { | |||
document.body.innerHTML = '<div class="page-content"></div>'; | |||
showGlobalErrorMessage('test msg 1'); | |||
showGlobalErrorMessage('test msg 2'); | |||
showGlobalErrorMessage('test msg 1'); // duplicated | |||
expect(document.body.innerHTML).toContain('>test msg 1 (2)<'); | |||
expect(document.body.innerHTML).toContain('>test msg 2<'); | |||
expect(document.querySelectorAll('.js-global-error').length).toEqual(2); | |||
}); |
@@ -1,3 +1,5 @@ | |||
window.__webpack_public_path__ = ''; | |||
window.config = { | |||
csrfToken: 'test-csrf-token-123456', | |||
pageData: {}, |