mirror of
https://github.com/go-gitea/gitea
synced 2025-12-07 05:18:29 +00:00
Enable TypeScript strictNullChecks (#35843)
A big step towards enabling strict mode in Typescript. There was definitely a good share of potential bugs while refactoring this. When in doubt, I opted to keep the potentially broken behaviour. Notably, the `DOMEvent` type is gone, it was broken and we're better of with type assertions on `e.target`. --------- Signed-off-by: silverwind <me@silverwind.io> Signed-off-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -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<HeatmapLocale>;
|
||||
@@ -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<HTMLElement>('.vch__external-legend-wrapper');
|
||||
const legend = document.querySelector<HTMLElement>('.vch__external-legend-wrapper')!;
|
||||
legend.setAttribute('viewBox', '12 0 80 10');
|
||||
legend.style.marginRight = '-12px';
|
||||
});
|
||||
|
||||
@@ -11,15 +11,17 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const loading = shallowRef(false);
|
||||
const issue = shallowRef<Issue>(null);
|
||||
const issue = shallowRef<Issue | null>(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;
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<Commit>,
|
||||
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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<HTMLAnchorElement>('.line-num').click();
|
||||
logLine.querySelector<HTMLAnchorElement>('.line-num')!.click();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
// @ts-expect-error - module exports no types
|
||||
import {VueBarGraph} from 'vue-bar-graph';
|
||||
import {computed, onMounted, shallowRef, useTemplateRef} from 'vue';
|
||||
import {computed, onMounted, shallowRef, useTemplateRef, type ShallowRef} from 'vue';
|
||||
|
||||
const colors = shallowRef({
|
||||
barColor: 'green',
|
||||
@@ -41,8 +41,8 @@ const graphWidth = computed(() => {
|
||||
return activityTopAuthors.length * 40;
|
||||
});
|
||||
|
||||
const styleElement = useTemplateRef('styleElement');
|
||||
const altStyleElement = useTemplateRef('altStyleElement');
|
||||
const styleElement = useTemplateRef('styleElement') as Readonly<ShallowRef<HTMLDivElement>>;
|
||||
const altStyleElement = useTemplateRef('altStyleElement') as Readonly<ShallowRef<HTMLDivElement>>;
|
||||
|
||||
onMounted(() => {
|
||||
const refStyle = window.getComputedStyle(styleElement.value);
|
||||
|
||||
@@ -20,7 +20,10 @@ type TabLoadingStates = Record<SelectedTab, '' | 'loading' | 'done'>
|
||||
export default defineComponent({
|
||||
components: {SvgIcon},
|
||||
props: {
|
||||
elRoot: HTMLElement,
|
||||
elRoot: {
|
||||
type: HTMLElement,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
const shouldShowTabBranches = this.elRoot.getAttribute('data-show-tab-branches') === 'true';
|
||||
@@ -33,28 +36,28 @@ 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'),
|
||||
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'),
|
||||
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',
|
||||
@@ -92,7 +95,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: {
|
||||
|
||||
@@ -174,7 +174,7 @@ export default defineComponent({
|
||||
user.max_contribution_type = 0;
|
||||
const filteredWeeks = user.weeks.filter((week: Record<string, number>) => {
|
||||
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 ?? undefined,
|
||||
max: this.xAxisMax ?? undefined,
|
||||
type: 'time',
|
||||
grid: {
|
||||
display: false,
|
||||
@@ -334,7 +334,7 @@ export default defineComponent({
|
||||
<div class="ui header tw-flex tw-items-center tw-justify-between">
|
||||
<div>
|
||||
<relative-time
|
||||
v-if="xAxisMin > 0"
|
||||
v-if="xAxisMin && xAxisMin > 0"
|
||||
format="datetime"
|
||||
year="numeric"
|
||||
month="short"
|
||||
@@ -346,7 +346,7 @@ export default defineComponent({
|
||||
</relative-time>
|
||||
{{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: "-" }}
|
||||
<relative-time
|
||||
v-if="xAxisMax > 0"
|
||||
v-if="xAxisMax && xAxisMax > 0"
|
||||
format="datetime"
|
||||
year="numeric"
|
||||
month="short"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch, nextTick, useTemplateRef, onMounted, onUnmounted } from 'vue';
|
||||
import {ref, computed, watch, nextTick, useTemplateRef, onMounted, onUnmounted, type ShallowRef} from 'vue';
|
||||
import {generateElemId} from '../utils/dom.ts';
|
||||
import { GET } from '../modules/fetch.ts';
|
||||
import { filterRepoFilesWeighted } from '../features/repo-findfile.ts';
|
||||
import { pathEscapeSegments } from '../utils/url.ts';
|
||||
import { SvgIcon } from '../svg.ts';
|
||||
import {GET} from '../modules/fetch.ts';
|
||||
import {filterRepoFilesWeighted} from '../features/repo-findfile.ts';
|
||||
import {pathEscapeSegments} from '../utils/url.ts';
|
||||
import {SvgIcon} from '../svg.ts';
|
||||
import {throttle} from 'throttle-debounce';
|
||||
|
||||
const props = defineProps({
|
||||
@@ -15,8 +15,8 @@ const props = defineProps({
|
||||
placeholder: { type: String, required: true },
|
||||
});
|
||||
|
||||
const refElemInput = useTemplateRef<HTMLInputElement>('searchInput');
|
||||
const refElemPopup = useTemplateRef<HTMLElement>('searchPopup');
|
||||
const refElemInput = useTemplateRef('searchInput') as Readonly<ShallowRef<HTMLInputElement>>;
|
||||
const refElemPopup = useTemplateRef('searchPopup') as Readonly<ShallowRef<HTMLDivElement>>;
|
||||
|
||||
const searchQuery = ref('');
|
||||
const allFiles = ref<string[]>([]);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import ViewFileTreeItem from './ViewFileTreeItem.vue';
|
||||
import {onMounted, useTemplateRef} from 'vue';
|
||||
import {onMounted, useTemplateRef, type ShallowRef} from 'vue';
|
||||
import {createViewFileTreeStore} from './ViewFileTreeStore.ts';
|
||||
|
||||
const elRoot = useTemplateRef('elRoot');
|
||||
const elRoot = useTemplateRef('elRoot') as Readonly<ShallowRef<HTMLDivElement>>;;
|
||||
|
||||
const props = defineProps({
|
||||
repoLink: {type: String, required: true},
|
||||
@@ -24,7 +24,7 @@ onMounted(async () => {
|
||||
|
||||
<template>
|
||||
<div class="view-file-tree-items" ref="elRoot">
|
||||
<ViewFileTreeItem v-for="item in store.rootFiles" :key="item.name" :item="item" :store="store"/>
|
||||
<ViewFileTreeItem v-for="item in store.rootFiles" :key="item.entryName" :item="item" :store="store"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Item>,
|
||||
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);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user