Enable strict TypeScript, add errorMessage helper (#37292)
Enable full TypeScript `strict` mode and fix issues discovered during this refactor. Introduced a `errorMessage` helper function to cleanly extract a error messages from the `unknown` type. Signed-off-by: silverwind <me@silverwind.io> Co-authored-by: Claude (claude-opus-4-7) <noreply@anthropic.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import {showTemporaryTooltip} from '../../modules/tippy.ts';
|
||||
import {POST} from '../../modules/fetch.ts';
|
||||
import {registerGlobalInitFunc} from '../../modules/observer.ts';
|
||||
import {queryElems} from '../../utils/dom.ts';
|
||||
import {errorMessage} from '../../modules/errors.ts';
|
||||
import {submitFormFetchAction} from '../common-fetch-action.ts';
|
||||
|
||||
const {appSubUrl} = window.config;
|
||||
@@ -26,7 +27,7 @@ function initSystemConfigAutoCheckbox(el: HTMLInputElement) {
|
||||
const json: Record<string, any> = await resp.json();
|
||||
if (json.errorMessage) throw new Error(json.errorMessage);
|
||||
} catch (ex) {
|
||||
showTemporaryTooltip(el, ex.toString());
|
||||
showTemporaryTooltip(el, errorMessage(ex));
|
||||
el.checked = !el.checked;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {getCurrentLocale} from '../utils.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
import {localUserSettings} from '../modules/user-settings.ts';
|
||||
|
||||
@@ -46,7 +47,7 @@ export async function initCitationFileCopyContent() {
|
||||
try {
|
||||
await initInputCitationValue(citationCopyApa, citationCopyBibtex);
|
||||
} catch (e) {
|
||||
console.error(`initCitationFileCopyContent error: ${e}`, e);
|
||||
console.error(`initCitationFileCopyContent error: ${errorMessage(e)}`, e);
|
||||
return;
|
||||
}
|
||||
updateUi();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {GET, request} from '../modules/fetch.ts';
|
||||
import {hideToastsAll, showErrorToast} from '../modules/toast.ts';
|
||||
import {addDelegatedEventListener, createElementFromHTML} from '../utils/dom.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {confirmModal, createConfirmModal} from './comp/ConfirmModal.ts';
|
||||
import {ignoreAreYouSure} from '../vendor/jquery.are-you-sure.ts';
|
||||
import {registerGlobalSelectorFunc} from '../modules/observer.ts';
|
||||
@@ -134,10 +135,10 @@ async function performActionRequest(el: HTMLElement, opt: FetchActionOpts) {
|
||||
return;
|
||||
}
|
||||
await handleFetchActionError(resp);
|
||||
} catch (e) {
|
||||
if (e.name !== 'AbortError') {
|
||||
console.error(`Fetch action request error:`, e);
|
||||
showErrorToast(`Error: ${e.message ?? e}`);
|
||||
} catch (err) {
|
||||
if ((err as Error).name !== 'AbortError') {
|
||||
console.error(`Fetch action request error:`, err);
|
||||
showErrorToast(`Error: ${errorMessage(err)}`);
|
||||
}
|
||||
} finally {
|
||||
toggleLoadingIndicator(el, opt, false);
|
||||
|
||||
@@ -71,26 +71,26 @@ export class ComboMarkdownEditor {
|
||||
|
||||
options: ComboMarkdownEditorOptions;
|
||||
|
||||
tabEditor: HTMLElement;
|
||||
tabPreviewer: HTMLElement;
|
||||
tabEditor?: HTMLElement;
|
||||
tabPreviewer?: HTMLElement;
|
||||
|
||||
supportEasyMDE: boolean;
|
||||
supportEasyMDE!: boolean;
|
||||
easyMDE: any;
|
||||
easyMDEToolbarActions: any;
|
||||
easyMDEToolbarDefault: any;
|
||||
|
||||
textarea: ComboMarkdownEditorTextarea;
|
||||
textareaMarkdownToolbar: HTMLElement;
|
||||
textarea!: ComboMarkdownEditorTextarea;
|
||||
textareaMarkdownToolbar!: HTMLElement;
|
||||
textareaAutosize: any;
|
||||
|
||||
buttonMonospace: HTMLButtonElement;
|
||||
buttonMonospace!: HTMLButtonElement;
|
||||
|
||||
dropzone: HTMLElement | null;
|
||||
dropzone: HTMLElement | null = null;
|
||||
attachedDropzoneInst: any;
|
||||
|
||||
previewMode: string;
|
||||
previewUrl: string;
|
||||
previewContext: string;
|
||||
previewMode!: string;
|
||||
previewUrl!: string;
|
||||
previewContext!: string;
|
||||
|
||||
constructor(container: ComboMarkdownEditorContainer, options:ComboMarkdownEditorOptions = {}) {
|
||||
if (container._giteaComboMarkdownEditor) throw new Error('ComboMarkdownEditor already initialized');
|
||||
@@ -291,7 +291,7 @@ export class ComboMarkdownEditor {
|
||||
}
|
||||
|
||||
switchTabToEditor() {
|
||||
this.tabEditor.click();
|
||||
this.tabEditor!.click(); // when this function is called, the tab must exist
|
||||
}
|
||||
|
||||
prepareEasyMDEToolbarActions() {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {showTemporaryTooltip} from '../modules/tippy.ts';
|
||||
import {GET, POST} from '../modules/fetch.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {createElementFromHTML, createElementFromAttrs} from '../utils/dom.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {isImageFile, isVideoFile} from '../utils.ts';
|
||||
import type Dropzone from '@deltablot/dropzone';
|
||||
|
||||
@@ -149,7 +150,7 @@ export async function initDropzone(dropzoneEl: HTMLElement) {
|
||||
} catch (error) {
|
||||
// TODO: if listing the existing attachments failed, it should stop from operating the content or attachments,
|
||||
// otherwise the attachments might be lost.
|
||||
showErrorToast(`Failed to load attachments: ${error}`);
|
||||
showErrorToast(`Failed to load attachments: ${errorMessage(error)}`);
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import type {InplaceRenderPlugin} from '../render/plugin.ts';
|
||||
import {newInplacePluginPdfViewer} from '../render/plugins/inplace-pdf-viewer.ts';
|
||||
import {registerGlobalInitFunc} from '../modules/observer.ts';
|
||||
import {createElementFromHTML} from '../utils/dom.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {html} from '../utils/html.ts';
|
||||
import {basename} from '../utils.ts';
|
||||
|
||||
@@ -30,7 +31,7 @@ async function renderRawFileToContainer(container: HTMLElement, rawFileLink: str
|
||||
rendered = true;
|
||||
}
|
||||
} catch (e) {
|
||||
errorMsg = `${e}`;
|
||||
errorMsg = errorMessage(e);
|
||||
} finally {
|
||||
container.classList.remove('is-loading');
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ function createContext(imageAfter: HTMLImageElement, imageBefore: HTMLImageEleme
|
||||
}
|
||||
|
||||
class ImageDiff {
|
||||
containerEl: HTMLElement;
|
||||
diffContainerWidth: number;
|
||||
containerEl!: HTMLElement;
|
||||
diffContainerWidth!: number;
|
||||
|
||||
async init(containerEl: HTMLElement) {
|
||||
this.containerEl = containerEl;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {queryElems} from '../utils/dom.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {POST} from '../modules/fetch.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {sleep} from '../utils.ts';
|
||||
@@ -26,7 +27,7 @@ async function onDownloadArchive(e: Event) {
|
||||
window.location.href = el.href; // the archive is ready, start real downloading
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
showErrorToast(`Failed to download the archive: ${e}`, {duration: 2500});
|
||||
showErrorToast(`Failed to download the archive: ${errorMessage(e)}`, {duration: 2500});
|
||||
} finally {
|
||||
targetLoading.classList.remove('is-loading', 'loading-icon-2px');
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {initViewedCheckboxListenerFor, initExpandAndCollapseFilesButton} from '.
|
||||
import {initImageDiff} from './imagediff.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {queryElemSiblings, hideElem, showElem, animateOnce, addDelegatedEventListener, createElementFromHTML, queryElems} from '../utils/dom.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {POST, GET} from '../modules/fetch.ts';
|
||||
import {createTippy} from '../modules/tippy.ts';
|
||||
import {invertFileFolding} from './file-fold.ts';
|
||||
@@ -85,7 +86,7 @@ function initRepoDiffConversationForm() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
showErrorToast(`Submit form failed: ${error}`);
|
||||
showErrorToast(`Submit form failed: ${errorMessage(error)}`);
|
||||
} finally {
|
||||
form?.classList.remove('is-loading');
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {getComboMarkdownEditor, initComboMarkdownEditor, ComboMarkdownEditor} fr
|
||||
import {POST} from '../modules/fetch.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {hideElem, querySingleVisibleElem, showElem} from '../utils/dom.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {triggerUploadStateChanged} from './comp/EditorUpload.ts';
|
||||
import {convertHtmlToMarkdown} from '../markup/html2markdown.ts';
|
||||
import {applyAreYouSure, reinitializeAreYouSure} from '../vendor/jquery.are-you-sure.ts';
|
||||
@@ -73,7 +74,7 @@ async function tryOnEditContent(e: Event) {
|
||||
}
|
||||
comboMarkdownEditor.dropzoneSubmitReload();
|
||||
} catch (error) {
|
||||
showErrorToast(`Failed to save the content: ${error}`);
|
||||
showErrorToast(`Failed to save the content: ${errorMessage(error)}`);
|
||||
console.error(error);
|
||||
} finally {
|
||||
renderContent.classList.remove('is-loading');
|
||||
|
||||
@@ -2,6 +2,7 @@ import {updateIssuesMeta} from './repo-common.ts';
|
||||
import {toggleElem, queryElems, isElemVisible} from '../utils/dom.ts';
|
||||
import {html, htmlRaw} from '../utils/html.ts';
|
||||
import {confirmModal} from './comp/ConfirmModal.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {createSortable} from '../modules/sortable.ts';
|
||||
import {DELETE, POST} from '../modules/fetch.ts';
|
||||
@@ -87,7 +88,9 @@ function initRepoIssueListCheckboxes() {
|
||||
await updateIssuesMeta(url, action, issueIDs, elementId);
|
||||
window.location.reload();
|
||||
} catch (err) {
|
||||
showErrorToast(err.responseJSON?.error ?? err.message);
|
||||
// FIXME: this logic (including updateIssuesMeta) is not right, should refactor to our JSONError framework
|
||||
const e = err as {responseJSON?: {error: string}};
|
||||
showErrorToast(e.responseJSON?.error ?? errorMessage(err));
|
||||
}
|
||||
},
|
||||
));
|
||||
|
||||
@@ -2,6 +2,7 @@ import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
import {GET, POST} from '../modules/fetch.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {addDelegatedEventListener, queryElemChildren, queryElems, toggleElem} from '../utils/dom.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {parseDom} from '../utils.ts';
|
||||
|
||||
export function syncIssueMainContentTimelineItems(oldMainContent: Element, newMainContent: Element) {
|
||||
@@ -42,7 +43,7 @@ export class IssueSidebarComboList {
|
||||
elDropdown: HTMLElement;
|
||||
elList: HTMLElement | null;
|
||||
elComboValue: HTMLInputElement;
|
||||
initialValues: string[];
|
||||
initialValues: string[] = [];
|
||||
container: HTMLElement;
|
||||
|
||||
elIssueMainContent: HTMLElement;
|
||||
@@ -129,7 +130,7 @@ export class IssueSidebarComboList {
|
||||
await this.reloadPagePartially();
|
||||
} catch (e) {
|
||||
console.error('Failed to update to backend', e);
|
||||
showErrorToast(`Failed to update to backend: ${e}`);
|
||||
showErrorToast(`Failed to update to backend: ${errorMessage(e)}`);
|
||||
} finally {
|
||||
this.elIssueSidebar.classList.remove('is-loading');
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {htmlEscape} from '../utils/html.ts';
|
||||
import {createTippy} from '../modules/tippy.ts';
|
||||
import {
|
||||
@@ -425,7 +426,7 @@ export function initRepoIssueTitleEdit() {
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showErrorToast(error.message);
|
||||
showErrorToast(errorMessage(error));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import {createSortable} from '../modules/sortable.ts';
|
||||
import {POST} from '../modules/fetch.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {queryElemChildren} from '../utils/dom.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
|
||||
export function initRepoSettingsBranchesDrag() {
|
||||
const protectedBranchesList = document.querySelector<HTMLElement>('#protected-branches-list');
|
||||
@@ -23,8 +24,7 @@ export function initRepoSettingsBranchesDrag() {
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
const errorMessage = String(err);
|
||||
showErrorToast(`Failed to update branch protection rule priority:, error: ${errorMessage}`);
|
||||
showErrorToast(`Failed to update branch protection rule priority: ${errorMessage(err)}`);
|
||||
}
|
||||
})();
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {encodeURLEncodedBase64, decodeURLEncodedBase64} from '../utils.ts';
|
||||
import {hideElem, showElem} from '../utils/dom.ts';
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {GET, POST} from '../modules/fetch.ts';
|
||||
|
||||
const {appSubUrl} = window.config;
|
||||
@@ -80,7 +81,7 @@ async function loginPasskey() {
|
||||
|
||||
window.location.href = reply?.redirect ?? `${appSubUrl}/`;
|
||||
} catch (err) {
|
||||
webAuthnError('general', err.message);
|
||||
webAuthnError('general', errorMessage(err));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +105,7 @@ async function login2FA() {
|
||||
await verifyAssertion(credential);
|
||||
} catch (err) {
|
||||
if (!options.publicKey.extensions?.appid) {
|
||||
webAuthnError('general', err.message);
|
||||
webAuthnError('general', errorMessage(err));
|
||||
return;
|
||||
}
|
||||
delete options.publicKey.extensions.appid;
|
||||
@@ -114,7 +115,7 @@ async function login2FA() {
|
||||
});
|
||||
await verifyAssertion(credential);
|
||||
} catch (err) {
|
||||
webAuthnError('general', err.message);
|
||||
webAuthnError('general', errorMessage(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,6 +263,6 @@ async function webAuthnRegisterRequest() {
|
||||
});
|
||||
await webauthnRegistered(credential);
|
||||
} catch (err) {
|
||||
webAuthnError('unknown', err);
|
||||
webAuthnError('unknown', errorMessage(err));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user