diff --git a/tsconfig.json b/tsconfig.json index 1daf4b7233b60..2466faf592c82 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -40,7 +40,7 @@ "strictBindCallApply": true, "strictBuiltinIteratorReturn": true, "strictFunctionTypes": true, - "strictNullChecks": false, + "strictNullChecks": true, "stripInternal": true, "verbatimModuleSyntax": true, "types": [ diff --git a/web_src/js/bootstrap.ts b/web_src/js/bootstrap.ts index 4d3f39f5bfa71..a94e1d66b0cc0 100644 --- a/web_src/js/bootstrap.ts +++ b/web_src/js/bootstrap.ts @@ -35,7 +35,7 @@ export function showGlobalErrorMessage(msg: string, msgType: Intent = 'error') { 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.querySelector('.ui.message').textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); + msgDiv.querySelector('.ui.message')!.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); msgContainer.prepend(msgDiv); } diff --git a/web_src/js/components/ActivityHeatmap.vue b/web_src/js/components/ActivityHeatmap.vue index 296cb61cff516..ab6fbd543d9fa 100644 --- a/web_src/js/components/ActivityHeatmap.vue +++ b/web_src/js/components/ActivityHeatmap.vue @@ -5,7 +5,7 @@ import {onMounted, shallowRef} from 'vue'; import type {Value as HeatmapValue, Locale as HeatmapLocale} from '@silverwind/vue3-calendar-heatmap'; defineProps<{ - values?: HeatmapValue[]; + values: HeatmapValue[]; locale: { textTotalContributions: string; heatMapLocale: Partial; @@ -28,7 +28,7 @@ const endDate = shallowRef(new Date()); onMounted(() => { // work around issue with first legend color being rendered twice and legend cut off - const legend = document.querySelector('.vch__external-legend-wrapper'); + const legend = document.querySelector('.vch__external-legend-wrapper')!; legend.setAttribute('viewBox', '12 0 80 10'); legend.style.marginRight = '-12px'; }); diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index 31db902adce96..733144aae1a2f 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -11,15 +11,17 @@ const props = defineProps<{ }>(); const loading = shallowRef(false); -const issue = shallowRef(null); +const issue = shallowRef(null); const renderedLabels = shallowRef(''); const errorMessage = shallowRef(''); const createdAt = computed(() => { + if (!issue?.value) return ''; return new Date(issue.value.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'}); }); const body = computed(() => { + if (!issue?.value) return ''; const body = issue.value.body.replace(/\n+/g, ' '); return body.length > 85 ? `${body.substring(0, 85)}…` : body; }); diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index e938814ec6c1b..e1f8475ea83a5 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -110,9 +110,9 @@ export default defineComponent({ }, mounted() { - const el = document.querySelector('#dashboard-repo-list'); + const el = document.querySelector('#dashboard-repo-list')!; this.changeReposFilter(this.reposFilter); - fomanticQuery(el.querySelector('.ui.dropdown')).dropdown(); + fomanticQuery(el.querySelector('.ui.dropdown')!).dropdown(); this.textArchivedFilterTitles = { 'archived': this.textShowOnlyArchived, diff --git a/web_src/js/components/DiffCommitSelector.vue b/web_src/js/components/DiffCommitSelector.vue index e9aa3c67442fa..fcc7af1fa08c9 100644 --- a/web_src/js/components/DiffCommitSelector.vue +++ b/web_src/js/components/DiffCommitSelector.vue @@ -23,7 +23,7 @@ type CommitListResult = { export default defineComponent({ components: {SvgIcon}, data: () => { - const el = document.querySelector('#diff-commit-select'); + const el = document.querySelector('#diff-commit-select')!; return { menuVisible: false, isLoading: false, @@ -35,7 +35,7 @@ export default defineComponent({ mergeBase: el.getAttribute('data-merge-base'), commits: [] as Array, hoverActivated: false, - lastReviewCommitSha: '', + lastReviewCommitSha: '' as string | null, uniqueIdMenu: generateElemId('diff-commit-selector-menu-'), uniqueIdShowAll: generateElemId('diff-commit-selector-show-all-'), }; @@ -165,7 +165,7 @@ export default defineComponent({ }, /** Called when user clicks on since last review */ changesSinceLastReviewClick() { - window.location.assign(`${this.issueLink}/files/${this.lastReviewCommitSha}..${this.commits.at(-1).id}${this.queryParams}`); + window.location.assign(`${this.issueLink}/files/${this.lastReviewCommitSha}..${this.commits.at(-1)!.id}${this.queryParams}`); }, /** Clicking on a single commit opens this specific commit */ commitClicked(commitId: string, newWindow = false) { @@ -193,7 +193,7 @@ export default defineComponent({ // find all selected commits and generate a link const firstSelected = this.commits.findIndex((x) => x.selected); const lastSelected = this.commits.findLastIndex((x) => x.selected); - let beforeCommitID: string; + let beforeCommitID: string | null = null; if (firstSelected === 0) { beforeCommitID = this.mergeBase; } else { @@ -204,7 +204,7 @@ export default defineComponent({ if (firstSelected === lastSelected) { // if the start and end are the same, we show this single commit window.location.assign(`${this.issueLink}/commits/${afterCommitID}${this.queryParams}`); - } else if (beforeCommitID === this.mergeBase && afterCommitID === this.commits.at(-1).id) { + } else if (beforeCommitID === this.mergeBase && afterCommitID === this.commits.at(-1)!.id) { // if the first commit is selected and the last commit is selected, we show all commits window.location.assign(`${this.issueLink}/files${this.queryParams}`); } else { diff --git a/web_src/js/components/DiffFileTree.vue b/web_src/js/components/DiffFileTree.vue index 981d10c1c16fc..e2934b967eb0e 100644 --- a/web_src/js/components/DiffFileTree.vue +++ b/web_src/js/components/DiffFileTree.vue @@ -12,14 +12,14 @@ const store = diffTreeStore(); onMounted(() => { // Default to true if unset store.fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) !== 'false'; - document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', toggleVisibility); + document.querySelector('.diff-toggle-file-tree-button')!.addEventListener('click', toggleVisibility); hashChangeListener(); window.addEventListener('hashchange', hashChangeListener); }); onUnmounted(() => { - document.querySelector('.diff-toggle-file-tree-button').removeEventListener('click', toggleVisibility); + document.querySelector('.diff-toggle-file-tree-button')!.removeEventListener('click', toggleVisibility); window.removeEventListener('hashchange', hashChangeListener); }); @@ -33,7 +33,7 @@ function expandSelectedFile() { if (store.selectedItem) { const box = document.querySelector(store.selectedItem); const folded = box?.getAttribute('data-folded') === 'true'; - if (folded) setFileFolding(box, box.querySelector('.fold-file'), false); + if (folded) setFileFolding(box, box.querySelector('.fold-file')!, false); } } @@ -48,10 +48,10 @@ function updateVisibility(visible: boolean) { } function updateState(visible: boolean) { - const btn = document.querySelector('.diff-toggle-file-tree-button'); + const btn = document.querySelector('.diff-toggle-file-tree-button')!; const [toShow, toHide] = btn.querySelectorAll('.icon'); - const tree = document.querySelector('#diff-file-tree'); - const newTooltip = btn.getAttribute(visible ? 'data-hide-text' : 'data-show-text'); + const tree = document.querySelector('#diff-file-tree')!; + const newTooltip = btn.getAttribute(visible ? 'data-hide-text' : 'data-show-text')!; btn.setAttribute('data-tooltip-content', newTooltip); toggleElem(tree, visible); toggleElem(toShow, !visible); diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 300f635793456..4456db186a925 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -402,7 +402,7 @@ export default defineComponent({ } // auto-scroll to the last log line of the last step - let autoScrollJobStepElement: HTMLElement; + let autoScrollJobStepElement: HTMLElement | undefined; for (let stepIndex = 0; stepIndex < this.currentJob.steps.length; stepIndex++) { if (!autoScrollStepIndexes.get(stepIndex)) continue; autoScrollJobStepElement = this.getJobStepLogsContainer(stepIndex); @@ -468,7 +468,7 @@ export default defineComponent({ } const logLine = this.elStepsContainer().querySelector(selectedLogStep); if (!logLine) return; - logLine.querySelector('.line-num').click(); + logLine.querySelector('.line-num')!.click(); }, }, }); diff --git a/web_src/js/components/RepoActivityTopAuthors.vue b/web_src/js/components/RepoActivityTopAuthors.vue index 5a925f99431e1..bb1c968eac9ae 100644 --- a/web_src/js/components/RepoActivityTopAuthors.vue +++ b/web_src/js/components/RepoActivityTopAuthors.vue @@ -45,8 +45,8 @@ const styleElement = useTemplateRef('styleElement'); const altStyleElement = useTemplateRef('altStyleElement'); onMounted(() => { - const refStyle = window.getComputedStyle(styleElement.value); - const refAltStyle = window.getComputedStyle(altStyleElement.value); + const refStyle = window.getComputedStyle(styleElement.value!); + const refAltStyle = window.getComputedStyle(altStyleElement.value!); colors.value = { barColor: refStyle.backgroundColor, diff --git a/web_src/js/components/RepoBranchTagSelector.vue b/web_src/js/components/RepoBranchTagSelector.vue index a0bd975f57edd..6ddadc681b3ac 100644 --- a/web_src/js/components/RepoBranchTagSelector.vue +++ b/web_src/js/components/RepoBranchTagSelector.vue @@ -23,7 +23,7 @@ export default defineComponent({ elRoot: HTMLElement, }, data() { - const shouldShowTabBranches = this.elRoot.getAttribute('data-show-tab-branches') === 'true'; + const shouldShowTabBranches = this.elRoot!.getAttribute('data-show-tab-branches') === 'true'; return { csrfToken: window.config.csrfToken, allItems: [] as ListItem[], @@ -33,33 +33,33 @@ export default defineComponent({ activeItemIndex: 0, tabLoadingStates: {} as TabLoadingStates, - textReleaseCompare: this.elRoot.getAttribute('data-text-release-compare'), - textBranches: this.elRoot.getAttribute('data-text-branches'), - textTags: this.elRoot.getAttribute('data-text-tags'), - textFilterBranch: this.elRoot.getAttribute('data-text-filter-branch'), - textFilterTag: this.elRoot.getAttribute('data-text-filter-tag'), - textDefaultBranchLabel: this.elRoot.getAttribute('data-text-default-branch-label'), - textCreateTag: this.elRoot.getAttribute('data-text-create-tag'), - textCreateBranch: this.elRoot.getAttribute('data-text-create-branch'), - textCreateRefFrom: this.elRoot.getAttribute('data-text-create-ref-from'), - textNoResults: this.elRoot.getAttribute('data-text-no-results'), - textViewAllBranches: this.elRoot.getAttribute('data-text-view-all-branches'), - textViewAllTags: this.elRoot.getAttribute('data-text-view-all-tags'), + textReleaseCompare: this.elRoot!.getAttribute('data-text-release-compare')!, + textBranches: this.elRoot!.getAttribute('data-text-branches')!, + textTags: this.elRoot!.getAttribute('data-text-tags')!, + textFilterBranch: this.elRoot!.getAttribute('data-text-filter-branch')!, + textFilterTag: this.elRoot!.getAttribute('data-text-filter-tag')!, + textDefaultBranchLabel: this.elRoot!.getAttribute('data-text-default-branch-label')!, + textCreateTag: this.elRoot!.getAttribute('data-text-create-tag')!, + textCreateBranch: this.elRoot!.getAttribute('data-text-create-branch')!, + textCreateRefFrom: this.elRoot!.getAttribute('data-text-create-ref-from')!, + textNoResults: this.elRoot!.getAttribute('data-text-no-results')!, + textViewAllBranches: this.elRoot!.getAttribute('data-text-view-all-branches')!, + textViewAllTags: this.elRoot!.getAttribute('data-text-view-all-tags')!, - currentRepoDefaultBranch: this.elRoot.getAttribute('data-current-repo-default-branch'), - currentRepoLink: this.elRoot.getAttribute('data-current-repo-link'), - currentTreePath: this.elRoot.getAttribute('data-current-tree-path'), - currentRefType: this.elRoot.getAttribute('data-current-ref-type') as GitRefType, - currentRefShortName: this.elRoot.getAttribute('data-current-ref-short-name'), + currentRepoDefaultBranch: this.elRoot!.getAttribute('data-current-repo-default-branch')!, + currentRepoLink: this.elRoot!.getAttribute('data-current-repo-link')!, + currentTreePath: this.elRoot!.getAttribute('data-current-tree-path')!, + currentRefType: this.elRoot!.getAttribute('data-current-ref-type')! as GitRefType, + currentRefShortName: this.elRoot!.getAttribute('data-current-ref-short-name')!, - refLinkTemplate: this.elRoot.getAttribute('data-ref-link-template'), - refFormActionTemplate: this.elRoot.getAttribute('data-ref-form-action-template'), - dropdownFixedText: this.elRoot.getAttribute('data-dropdown-fixed-text'), + refLinkTemplate: this.elRoot!.getAttribute('data-ref-link-template')!, + refFormActionTemplate: this.elRoot!.getAttribute('data-ref-form-action-template')!, + dropdownFixedText: this.elRoot!.getAttribute('data-dropdown-fixed-text')!, showTabBranches: shouldShowTabBranches, - showTabTags: this.elRoot.getAttribute('data-show-tab-tags') === 'true', - allowCreateNewRef: this.elRoot.getAttribute('data-allow-create-new-ref') === 'true', - showViewAllRefsEntry: this.elRoot.getAttribute('data-show-view-all-refs-entry') === 'true', - enableFeed: this.elRoot.getAttribute('data-enable-feed') === 'true', + showTabTags: this.elRoot!.getAttribute('data-show-tab-tags') === 'true', + allowCreateNewRef: this.elRoot!.getAttribute('data-allow-create-new-ref') === 'true', + showViewAllRefsEntry: this.elRoot!.getAttribute('data-show-view-all-refs-entry') === 'true', + enableFeed: this.elRoot!.getAttribute('data-enable-feed') === 'true', }; }, computed: { @@ -92,7 +92,7 @@ export default defineComponent({ }).length; }, createNewRefFormActionUrl() { - return `${this.currentRepoLink}/branches/_new/${this.currentRefType}/${pathEscapeSegments(this.currentRefShortName)}`; + return `${this.currentRepoLink}/branches/_new/${this.currentRefType}/${pathEscapeSegments(this.currentRefShortName!)}`; }, }, watch: { diff --git a/web_src/js/components/RepoContributors.vue b/web_src/js/components/RepoContributors.vue index 08d63540e280b..05a58d4eaef8f 100644 --- a/web_src/js/components/RepoContributors.vue +++ b/web_src/js/components/RepoContributors.vue @@ -174,7 +174,7 @@ export default defineComponent({ user.max_contribution_type = 0; const filteredWeeks = user.weeks.filter((week: Record) => { const oneWeek = 7 * 24 * 60 * 60 * 1000; - if (week.week >= this.xAxisMin - oneWeek && week.week <= this.xAxisMax + oneWeek) { + if (week.week >= this.xAxisMin! - oneWeek && week.week <= this.xAxisMax! + oneWeek) { user.total_commits += week.commits; user.total_additions += week.additions; user.total_deletions += week.deletions; @@ -238,8 +238,8 @@ export default defineComponent({ }, updateOtherCharts({chart}: {chart: Chart}, reset: boolean = false) { - const minVal = Number(chart.options.scales.x.min); - const maxVal = Number(chart.options.scales.x.max); + const minVal = Number(chart.options.scales!.x!.min); + const maxVal = Number(chart.options.scales!.x!.max); if (reset) { this.xAxisMin = this.xAxisStart; this.xAxisMax = this.xAxisEnd; @@ -302,8 +302,8 @@ export default defineComponent({ }, scales: { x: { - min: this.xAxisMin, - max: this.xAxisMax, + min: this.xAxisMin!, + max: this.xAxisMax!, type: 'time', grid: { display: false, @@ -334,27 +334,27 @@ export default defineComponent({
- {{ new Date(xAxisMin) }} + {{ new Date(xAxisMin!) }} {{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: "-" }} - {{ new Date(xAxisMax) }} + {{ new Date(xAxisMax!) }}
diff --git a/web_src/js/components/ViewFileTree.vue b/web_src/js/components/ViewFileTree.vue index 1f90f9258670c..d1fdc7c8a8649 100644 --- a/web_src/js/components/ViewFileTree.vue +++ b/web_src/js/components/ViewFileTree.vue @@ -14,7 +14,7 @@ const props = defineProps({ const store = createViewFileTreeStore(props); onMounted(async () => { store.rootFiles = await store.loadChildren('', props.treePath); - elRoot.value.closest('.is-loading')?.classList?.remove('is-loading'); + elRoot.value!.closest('.is-loading')?.classList?.remove('is-loading'); window.addEventListener('popstate', (e) => { store.selectedItem = e.state?.treePath || ''; if (e.state?.url) store.loadViewContent(e.state.url); @@ -24,7 +24,7 @@ onMounted(async () => { diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 06d761dd65311..9a50adedaac7f 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -4,7 +4,7 @@ import {isPlainClick} from '../utils/dom.ts'; import {shallowRef} from 'vue'; import {type createViewFileTreeStore} from './ViewFileTreeStore.ts'; -type Item = { +export type Item = { entryName: string; entryMode: 'blob' | 'exec' | 'tree' | 'commit' | 'symlink' | 'unknown'; entryIcon: string; diff --git a/web_src/js/components/ViewFileTreeStore.ts b/web_src/js/components/ViewFileTreeStore.ts index 61d9168aa6c3a..211567d0a19dc 100644 --- a/web_src/js/components/ViewFileTreeStore.ts +++ b/web_src/js/components/ViewFileTreeStore.ts @@ -3,10 +3,11 @@ import {GET} from '../modules/fetch.ts'; import {pathEscapeSegments} from '../utils/url.ts'; import {createElementFromHTML} from '../utils/dom.ts'; import {html} from '../utils/html.ts'; +import type {Item} from './ViewFileTreeItem.vue'; export function createViewFileTreeStore(props: {repoLink: string, treePath: string, currentRefNameSubURL: string}) { const store = reactive({ - rootFiles: [], + rootFiles: [] as Array, selectedItem: props.treePath, async loadChildren(treePath: string, subPath: string = '') { @@ -28,7 +29,7 @@ export function createViewFileTreeStore(props: {repoLink: string, treePath: stri const u = new URL(url, window.origin); u.searchParams.set('only_content', 'true'); const response = await GET(u.href); - const elViewContent = document.querySelector('.repo-view-content'); + const elViewContent = document.querySelector('.repo-view-content')!; elViewContent.innerHTML = await response.text(); const elViewContentData = elViewContent.querySelector('.repo-view-content-data'); if (!elViewContentData) return; // if error occurs, there is no such element @@ -39,7 +40,7 @@ export function createViewFileTreeStore(props: {repoLink: string, treePath: stri async navigateTreeView(treePath: string) { const url = store.buildTreePathWebUrl(treePath); - window.history.pushState({treePath, url}, null, url); + window.history.pushState({treePath, url}, '', url); store.selectedItem = treePath; await store.loadViewContent(url); }, diff --git a/web_src/js/features/admin/common.ts b/web_src/js/features/admin/common.ts index dd5b1f464d45a..c019b80671ecc 100644 --- a/web_src/js/features/admin/common.ts +++ b/web_src/js/features/admin/common.ts @@ -63,7 +63,7 @@ function initAdminAuthentication() { function onUsePagedSearchChange() { const searchPageSizeElements = document.querySelectorAll('.search-page-size'); - if (document.querySelector('#use_paged_search').checked) { + if (document.querySelector('#use_paged_search')!.checked) { showElem('.search-page-size'); for (const el of searchPageSizeElements) { el.querySelector('input')?.setAttribute('required', 'required'); @@ -82,10 +82,10 @@ function initAdminAuthentication() { input.removeAttribute('required'); } - const provider = document.querySelector('#oauth2_provider').value; + const provider = document.querySelector('#oauth2_provider')!.value; switch (provider) { case 'openidConnect': - document.querySelector('.open_id_connect_auto_discovery_url input').setAttribute('required', 'required'); + document.querySelector('.open_id_connect_auto_discovery_url input')!.setAttribute('required', 'required'); showElem('.open_id_connect_auto_discovery_url'); break; default: { @@ -97,7 +97,7 @@ function initAdminAuthentication() { showElem('.oauth2_use_custom_url'); // show the checkbox } if (mustProvideCustomURLs) { - document.querySelector('#oauth2_use_custom_url').checked = true; // make the checkbox checked + document.querySelector('#oauth2_use_custom_url')!.checked = true; // make the checkbox checked } break; } @@ -109,17 +109,17 @@ function initAdminAuthentication() { } function onOAuth2UseCustomURLChange(applyDefaultValues: boolean) { - const provider = document.querySelector('#oauth2_provider').value; + const provider = document.querySelector('#oauth2_provider')!.value; hideElem('.oauth2_use_custom_url_field'); for (const input of document.querySelectorAll('.oauth2_use_custom_url_field input[required]')) { input.removeAttribute('required'); } const elProviderCustomUrlSettings = document.querySelector(`#${provider}_customURLSettings`); - if (elProviderCustomUrlSettings && document.querySelector('#oauth2_use_custom_url').checked) { + if (elProviderCustomUrlSettings && document.querySelector('#oauth2_use_custom_url')!.checked) { for (const custom of ['token_url', 'auth_url', 'profile_url', 'email_url', 'tenant']) { if (applyDefaultValues) { - document.querySelector(`#oauth2_${custom}`).value = document.querySelector(`#${provider}_${custom}`).value; + document.querySelector(`#oauth2_${custom}`)!.value = document.querySelector(`#${provider}_${custom}`)!.value; } const customInput = document.querySelector(`#${provider}_${custom}`); if (customInput && customInput.getAttribute('data-available') === 'true') { @@ -134,10 +134,10 @@ function initAdminAuthentication() { function onEnableLdapGroupsChange() { const checked = document.querySelector('.js-ldap-group-toggle')?.checked; - toggleElem(document.querySelector('#ldap-group-options'), checked); + toggleElem(document.querySelector('#ldap-group-options')!, checked); } - const elAuthType = document.querySelector('#auth_type'); + const elAuthType = document.querySelector('#auth_type')!; // New authentication if (isNewPage) { @@ -208,14 +208,14 @@ function initAdminAuthentication() { document.querySelector('#oauth2_provider')?.addEventListener('change', () => onOAuth2Change(true)); document.querySelector('#oauth2_use_custom_url')?.addEventListener('change', () => onOAuth2UseCustomURLChange(true)); - document.querySelector('.js-ldap-group-toggle').addEventListener('change', onEnableLdapGroupsChange); + document.querySelector('.js-ldap-group-toggle')!.addEventListener('change', onEnableLdapGroupsChange); } // Edit authentication if (isEditPage) { const authType = elAuthType.value; if (authType === '2' || authType === '5') { document.querySelector('#security_protocol')?.addEventListener('change', onSecurityProtocolChange); - document.querySelector('.js-ldap-group-toggle').addEventListener('change', onEnableLdapGroupsChange); + document.querySelector('.js-ldap-group-toggle')!.addEventListener('change', onEnableLdapGroupsChange); onEnableLdapGroupsChange(); if (authType === '2') { document.querySelector('#use_paged_search')?.addEventListener('change', onUsePagedSearchChange); @@ -227,10 +227,10 @@ function initAdminAuthentication() { } } - const elAuthName = document.querySelector('#auth_name'); + const elAuthName = document.querySelector('#auth_name')!; const onAuthNameChange = function () { // appSubUrl is either empty or is a path that starts with `/` and doesn't have a trailing slash. - document.querySelector('#oauth2-callback-url').textContent = `${window.location.origin}${appSubUrl}/user/oauth2/${encodeURIComponent(elAuthName.value)}/callback`; + document.querySelector('#oauth2-callback-url')!.textContent = `${window.location.origin}${appSubUrl}/user/oauth2/${encodeURIComponent(elAuthName.value)}/callback`; }; elAuthName.addEventListener('input', onAuthNameChange); onAuthNameChange(); @@ -240,13 +240,13 @@ function initAdminNotice() { const pageContent = document.querySelector('.page-content.admin.notice'); if (!pageContent) return; - const detailModal = document.querySelector('#detail-modal'); + const detailModal = document.querySelector('#detail-modal')!; // Attach view detail modals queryElems(pageContent, '.view-detail', (el) => el.addEventListener('click', (e) => { e.preventDefault(); - const elNoticeDesc = el.closest('tr').querySelector('.notice-description'); - const elModalDesc = detailModal.querySelector('.content pre'); + const elNoticeDesc = el.closest('tr')!.querySelector('.notice-description')!; + const elModalDesc = detailModal.querySelector('.content pre')!; elModalDesc.textContent = elNoticeDesc.textContent; fomanticQuery(detailModal).modal('show'); })); @@ -280,10 +280,10 @@ function initAdminNotice() { const data = new FormData(); for (const checkbox of checkboxes) { if (checkbox.checked) { - data.append('ids[]', checkbox.closest('.ui.checkbox').getAttribute('data-id')); + data.append('ids[]', checkbox.closest('.ui.checkbox')!.getAttribute('data-id')!); } } - await POST(this.getAttribute('data-link'), {data}); - window.location.href = this.getAttribute('data-redirect'); + await POST(this.getAttribute('data-link')!, {data}); + window.location.href = this.getAttribute('data-redirect')!; }); } diff --git a/web_src/js/features/admin/config.ts b/web_src/js/features/admin/config.ts index 16d7a2426f978..76f7c1db50ec3 100644 --- a/web_src/js/features/admin/config.ts +++ b/web_src/js/features/admin/config.ts @@ -11,7 +11,7 @@ export function initAdminConfigs(): void { el.addEventListener('change', async () => { try { const resp = await POST(`${appSubUrl}/-/admin/config`, { - data: new URLSearchParams({key: el.getAttribute('data-config-dyn-key'), value: String(el.checked)}), + data: new URLSearchParams({key: el.getAttribute('data-config-dyn-key')!, value: String(el.checked)}), }); const json: Record = await resp.json(); if (json.errorMessage) throw new Error(json.errorMessage); diff --git a/web_src/js/features/admin/selfcheck.ts b/web_src/js/features/admin/selfcheck.ts index 9f53378b52a76..903eb15c87d6f 100644 --- a/web_src/js/features/admin/selfcheck.ts +++ b/web_src/js/features/admin/selfcheck.ts @@ -7,7 +7,7 @@ export async function initAdminSelfCheck() { const elCheckByFrontend = document.querySelector('#self-check-by-frontend'); if (!elCheckByFrontend) return; - const elContent = document.querySelector('.page-content.admin .admin-setting-content'); + const elContent = document.querySelector('.page-content.admin .admin-setting-content')!; // send frontend self-check request const resp = await POST(`${appSubUrl}/-/admin/self_check`, { @@ -27,5 +27,5 @@ export async function initAdminSelfCheck() { // only show the "no problem" if there is no visible "self-check-problem" const hasProblem = Boolean(elContent.querySelectorAll('.self-check-problem:not(.tw-hidden)').length); - toggleElem(elContent.querySelector('.self-check-no-problem'), !hasProblem); + toggleElem(elContent.querySelector('.self-check-no-problem')!, !hasProblem); } diff --git a/web_src/js/features/captcha.ts b/web_src/js/features/captcha.ts index df234d0e5c85e..f3d153a036fd9 100644 --- a/web_src/js/features/captcha.ts +++ b/web_src/js/features/captcha.ts @@ -4,7 +4,7 @@ export async function initCaptcha() { const captchaEl = document.querySelector('#captcha'); if (!captchaEl) return; - const siteKey = captchaEl.getAttribute('data-sitekey'); + const siteKey = captchaEl.getAttribute('data-sitekey')!; const isDark = isDarkTheme(); const params = { @@ -43,7 +43,7 @@ export async function initCaptcha() { // @ts-expect-error TS2540: Cannot assign to 'INPUT_NAME' because it is a read-only property. mCaptcha.INPUT_NAME = 'm-captcha-response'; - const instanceURL = captchaEl.getAttribute('data-instance-url'); + const instanceURL = captchaEl.getAttribute('data-instance-url')!; new mCaptcha.default({ siteKey: { diff --git a/web_src/js/features/citation.ts b/web_src/js/features/citation.ts index 3c9fe0afc851e..d5ecb52e72a7f 100644 --- a/web_src/js/features/citation.ts +++ b/web_src/js/features/citation.ts @@ -31,15 +31,15 @@ export async function initCitationFileCopyContent() { if (!pageData.citationFileContent) return; - const citationCopyApa = document.querySelector('#citation-copy-apa'); - const citationCopyBibtex = document.querySelector('#citation-copy-bibtex'); + const citationCopyApa = document.querySelector('#citation-copy-apa')!; + const citationCopyBibtex = document.querySelector('#citation-copy-bibtex')!; const inputContent = document.querySelector('#citation-copy-content'); if ((!citationCopyApa && !citationCopyBibtex) || !inputContent) return; const updateUi = () => { const isBibtex = (localStorage.getItem('citation-copy-format') || defaultCitationFormat) === 'bibtex'; - const copyContent = (isBibtex ? citationCopyBibtex : citationCopyApa).getAttribute('data-text'); + const copyContent = (isBibtex ? citationCopyBibtex : citationCopyApa).getAttribute('data-text')!; inputContent.value = copyContent; citationCopyBibtex.classList.toggle('primary', isBibtex); citationCopyApa.classList.toggle('primary', !isBibtex); diff --git a/web_src/js/features/clipboard.ts b/web_src/js/features/clipboard.ts index 22c264d774678..d5e3b55f957ee 100644 --- a/web_src/js/features/clipboard.ts +++ b/web_src/js/features/clipboard.ts @@ -1,7 +1,6 @@ import {showTemporaryTooltip} from '../modules/tippy.ts'; import {toAbsoluteUrl} from '../utils.ts'; import {clippie} from 'clippie'; -import type {DOMEvent} from '../utils/dom.ts'; const {copy_success, copy_error} = window.config.i18n; @@ -10,15 +9,15 @@ const {copy_success, copy_error} = window.config.i18n; // - data-clipboard-target: Holds a selector for a or