mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 19:38:23 +00:00 
			
		
		
		
	Fix typescript errors in Vue files, fix regression in "Recent Commits" chart (#32649)
- Fix all typescript errors in `.vue` files - Fix regression from https://github.com/go-gitea/gitea/pull/32329 where "Recent Commits" chart would not render. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		| @@ -6,8 +6,17 @@ import {fomanticQuery} from '../modules/fomantic/base.ts'; | |||||||
|  |  | ||||||
| const {appSubUrl, assetUrlPrefix, pageData} = window.config; | const {appSubUrl, assetUrlPrefix, pageData} = window.config; | ||||||
|  |  | ||||||
|  | type CommitStatus = 'pending' | 'success' | 'error' | 'failure' | 'warning'; | ||||||
|  |  | ||||||
|  | type CommitStatusMap = { | ||||||
|  |   [status in CommitStatus]: { | ||||||
|  |     name: string, | ||||||
|  |     color: string, | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
| // make sure this matches templates/repo/commit_status.tmpl | // make sure this matches templates/repo/commit_status.tmpl | ||||||
| const commitStatus = { | const commitStatus: CommitStatusMap = { | ||||||
|   pending: {name: 'octicon-dot-fill', color: 'yellow'}, |   pending: {name: 'octicon-dot-fill', color: 'yellow'}, | ||||||
|   success: {name: 'octicon-check', color: 'green'}, |   success: {name: 'octicon-check', color: 'green'}, | ||||||
|   error: {name: 'gitea-exclamation', color: 'red'}, |   error: {name: 'gitea-exclamation', color: 'red'}, | ||||||
| @@ -281,18 +290,18 @@ const sfc = { | |||||||
|       return 'octicon-repo'; |       return 'octicon-repo'; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     statusIcon(status) { |     statusIcon(status: CommitStatus) { | ||||||
|       return commitStatus[status].name; |       return commitStatus[status].name; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     statusColor(status) { |     statusColor(status: CommitStatus) { | ||||||
|       return commitStatus[status].color; |       return commitStatus[status].color; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     reposFilterKeyControl(e) { |     reposFilterKeyControl(e) { | ||||||
|       switch (e.key) { |       switch (e.key) { | ||||||
|         case 'Enter': |         case 'Enter': | ||||||
|           document.querySelector('.repo-owner-name-list li.active a')?.click(); |           document.querySelector<HTMLAnchorElement>('.repo-owner-name-list li.active a')?.click(); | ||||||
|           break; |           break; | ||||||
|         case 'ArrowUp': |         case 'ArrowUp': | ||||||
|           if (this.activeIndex > 0) { |           if (this.activeIndex > 0) { | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ export default { | |||||||
|       issueLink: el.getAttribute('data-issuelink'), |       issueLink: el.getAttribute('data-issuelink'), | ||||||
|       locale: { |       locale: { | ||||||
|         filter_changes_by_commit: el.getAttribute('data-filter_changes_by_commit'), |         filter_changes_by_commit: el.getAttribute('data-filter_changes_by_commit'), | ||||||
|       }, |       } as Record<string, string>, | ||||||
|       commits: [], |       commits: [], | ||||||
|       hoverActivated: false, |       hoverActivated: false, | ||||||
|       lastReviewCommitSha: null, |       lastReviewCommitSha: null, | ||||||
| @@ -41,16 +41,16 @@ export default { | |||||||
|     this.$el.removeEventListener('keyup', this.onKeyUp); |     this.$el.removeEventListener('keyup', this.onKeyUp); | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     onBodyClick(event) { |     onBodyClick(event: MouseEvent) { | ||||||
|       // close this menu on click outside of this element when the dropdown is currently visible opened |       // close this menu on click outside of this element when the dropdown is currently visible opened | ||||||
|       if (this.$el.contains(event.target)) return; |       if (this.$el.contains(event.target)) return; | ||||||
|       if (this.menuVisible) { |       if (this.menuVisible) { | ||||||
|         this.toggleMenu(); |         this.toggleMenu(); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     onKeyDown(event) { |     onKeyDown(event: KeyboardEvent) { | ||||||
|       if (!this.menuVisible) return; |       if (!this.menuVisible) return; | ||||||
|       const item = document.activeElement; |       const item = document.activeElement as HTMLElement; | ||||||
|       if (!this.$el.contains(item)) return; |       if (!this.$el.contains(item)) return; | ||||||
|       switch (event.key) { |       switch (event.key) { | ||||||
|         case 'ArrowDown': // select next element |         case 'ArrowDown': // select next element | ||||||
| @@ -73,7 +73,7 @@ export default { | |||||||
|         if (commitIdx) this.highlight(this.commits[commitIdx]); |         if (commitIdx) this.highlight(this.commits[commitIdx]); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     onKeyUp(event) { |     onKeyUp(event: KeyboardEvent) { | ||||||
|       if (!this.menuVisible) return; |       if (!this.menuVisible) return; | ||||||
|       const item = document.activeElement; |       const item = document.activeElement; | ||||||
|       if (!this.$el.contains(item)) return; |       if (!this.$el.contains(item)) return; | ||||||
| @@ -95,7 +95,7 @@ export default { | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     /** Focus given element */ |     /** Focus given element */ | ||||||
|     focusElem(elem, prevElem) { |     focusElem(elem: HTMLElement, prevElem: HTMLElement) { | ||||||
|       if (elem) { |       if (elem) { | ||||||
|         elem.tabIndex = 0; |         elem.tabIndex = 0; | ||||||
|         if (prevElem) prevElem.tabIndex = -1; |         if (prevElem) prevElem.tabIndex = -1; | ||||||
| @@ -149,7 +149,7 @@ export default { | |||||||
|       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 */ |     /** Clicking on a single commit opens this specific commit */ | ||||||
|     commitClicked(commitId, newWindow = false) { |     commitClicked(commitId: string, newWindow = false) { | ||||||
|       const url = `${this.issueLink}/commits/${commitId}${this.queryParams}`; |       const url = `${this.issueLink}/commits/${commitId}${this.queryParams}`; | ||||||
|       if (newWindow) { |       if (newWindow) { | ||||||
|         window.open(url); |         window.open(url); | ||||||
|   | |||||||
| @@ -8,6 +8,8 @@ import { | |||||||
|   PointElement, |   PointElement, | ||||||
|   LineElement, |   LineElement, | ||||||
|   Filler, |   Filler, | ||||||
|  |   type ChartOptions, | ||||||
|  |   type ChartData, | ||||||
| } from 'chart.js'; | } from 'chart.js'; | ||||||
| import {GET} from '../modules/fetch.ts'; | import {GET} from '../modules/fetch.ts'; | ||||||
| import {Line as ChartLine} from 'vue-chartjs'; | import {Line as ChartLine} from 'vue-chartjs'; | ||||||
| @@ -16,6 +18,7 @@ import { | |||||||
|   firstStartDateAfterDate, |   firstStartDateAfterDate, | ||||||
|   fillEmptyStartDaysWithZeroes, |   fillEmptyStartDaysWithZeroes, | ||||||
|   type DayData, |   type DayData, | ||||||
|  |   type DayDataObject, | ||||||
| } from '../utils/time.ts'; | } from '../utils/time.ts'; | ||||||
| import {chartJsColors} from '../utils/color.ts'; | import {chartJsColors} from '../utils/color.ts'; | ||||||
| import {sleep} from '../utils.ts'; | import {sleep} from '../utils.ts'; | ||||||
| @@ -64,12 +67,12 @@ async function fetchGraphData() { | |||||||
|       } |       } | ||||||
|     } while (response.status === 202); |     } while (response.status === 202); | ||||||
|     if (response.ok) { |     if (response.ok) { | ||||||
|       data.value = await response.json(); |       const dayDataObject: DayDataObject = await response.json(); | ||||||
|       const weekValues = Object.values(data.value); |       const weekValues = Object.values(dayDataObject); | ||||||
|       const start = weekValues[0].week; |       const start = weekValues[0].week; | ||||||
|       const end = firstStartDateAfterDate(new Date()); |       const end = firstStartDateAfterDate(new Date()); | ||||||
|       const startDays = startDaysBetween(start, end); |       const startDays = startDaysBetween(start, end); | ||||||
|       data.value = fillEmptyStartDaysWithZeroes(startDays, data.value); |       data.value = fillEmptyStartDaysWithZeroes(startDays, dayDataObject); | ||||||
|       errorText.value = ''; |       errorText.value = ''; | ||||||
|     } else { |     } else { | ||||||
|       errorText.value = response.statusText; |       errorText.value = response.statusText; | ||||||
| @@ -81,7 +84,7 @@ async function fetchGraphData() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| function toGraphData(data) { | function toGraphData(data: Array<Record<string, any>>): ChartData<'line'> { | ||||||
|   return { |   return { | ||||||
|     datasets: [ |     datasets: [ | ||||||
|       { |       { | ||||||
| @@ -108,10 +111,9 @@ function toGraphData(data) { | |||||||
|   }; |   }; | ||||||
| } | } | ||||||
|  |  | ||||||
| const options = { | const options: ChartOptions<'line'> = { | ||||||
|   responsive: true, |   responsive: true, | ||||||
|   maintainAspectRatio: false, |   maintainAspectRatio: false, | ||||||
|   animation: true, |  | ||||||
|   plugins: { |   plugins: { | ||||||
|     legend: { |     legend: { | ||||||
|       display: true, |       display: true, | ||||||
|   | |||||||
| @@ -9,6 +9,9 @@ import { | |||||||
|   PointElement, |   PointElement, | ||||||
|   LineElement, |   LineElement, | ||||||
|   Filler, |   Filler, | ||||||
|  |   type ChartOptions, | ||||||
|  |   type ChartData, | ||||||
|  |   type Plugin, | ||||||
| } from 'chart.js'; | } from 'chart.js'; | ||||||
| import {GET} from '../modules/fetch.ts'; | import {GET} from '../modules/fetch.ts'; | ||||||
| import zoomPlugin from 'chartjs-plugin-zoom'; | import zoomPlugin from 'chartjs-plugin-zoom'; | ||||||
| @@ -22,8 +25,9 @@ import {chartJsColors} from '../utils/color.ts'; | |||||||
| import {sleep} from '../utils.ts'; | import {sleep} from '../utils.ts'; | ||||||
| import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; | import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; | ||||||
| import {fomanticQuery} from '../modules/fomantic/base.ts'; | import {fomanticQuery} from '../modules/fomantic/base.ts'; | ||||||
|  | import type {Entries} from 'type-fest'; | ||||||
|  |  | ||||||
| const customEventListener = { | const customEventListener: Plugin = { | ||||||
|   id: 'customEventListener', |   id: 'customEventListener', | ||||||
|   afterEvent: (chart, args, opts) => { |   afterEvent: (chart, args, opts) => { | ||||||
|     // event will be replayed from chart.update when reset zoom, |     // event will be replayed from chart.update when reset zoom, | ||||||
| @@ -65,10 +69,10 @@ export default { | |||||||
|   data: () => ({ |   data: () => ({ | ||||||
|     isLoading: false, |     isLoading: false, | ||||||
|     errorText: '', |     errorText: '', | ||||||
|     totalStats: {}, |     totalStats: {} as Record<string, any>, | ||||||
|     sortedContributors: {}, |     sortedContributors: {} as Record<string, any>, | ||||||
|     type: 'commits', |     type: 'commits', | ||||||
|     contributorsStats: [], |     contributorsStats: {} as Record<string, any>, | ||||||
|     xAxisStart: null, |     xAxisStart: null, | ||||||
|     xAxisEnd: null, |     xAxisEnd: null, | ||||||
|     xAxisMin: null, |     xAxisMin: null, | ||||||
| @@ -99,7 +103,7 @@ export default { | |||||||
|     async fetchGraphData() { |     async fetchGraphData() { | ||||||
|       this.isLoading = true; |       this.isLoading = true; | ||||||
|       try { |       try { | ||||||
|         let response; |         let response: Response; | ||||||
|         do { |         do { | ||||||
|           response = await GET(`${this.repoLink}/activity/contributors/data`); |           response = await GET(`${this.repoLink}/activity/contributors/data`); | ||||||
|           if (response.status === 202) { |           if (response.status === 202) { | ||||||
| @@ -112,7 +116,7 @@ export default { | |||||||
|           // below line might be deleted if we are sure go produces map always sorted by keys |           // below line might be deleted if we are sure go produces map always sorted by keys | ||||||
|           total.weeks = Object.fromEntries(Object.entries(total.weeks).sort()); |           total.weeks = Object.fromEntries(Object.entries(total.weeks).sort()); | ||||||
|  |  | ||||||
|           const weekValues = Object.values(total.weeks); |           const weekValues = Object.values(total.weeks) as any; | ||||||
|           this.xAxisStart = weekValues[0].week; |           this.xAxisStart = weekValues[0].week; | ||||||
|           this.xAxisEnd = firstStartDateAfterDate(new Date()); |           this.xAxisEnd = firstStartDateAfterDate(new Date()); | ||||||
|           const startDays = startDaysBetween(this.xAxisStart, this.xAxisEnd); |           const startDays = startDaysBetween(this.xAxisStart, this.xAxisEnd); | ||||||
| @@ -120,7 +124,7 @@ export default { | |||||||
|           this.xAxisMin = this.xAxisStart; |           this.xAxisMin = this.xAxisStart; | ||||||
|           this.xAxisMax = this.xAxisEnd; |           this.xAxisMax = this.xAxisEnd; | ||||||
|           this.contributorsStats = {}; |           this.contributorsStats = {}; | ||||||
|           for (const [email, user] of Object.entries(rest)) { |           for (const [email, user] of Object.entries(rest) as Entries<Record<string, Record<string, any>>>) { | ||||||
|             user.weeks = fillEmptyStartDaysWithZeroes(startDays, user.weeks); |             user.weeks = fillEmptyStartDaysWithZeroes(startDays, user.weeks); | ||||||
|             this.contributorsStats[email] = user; |             this.contributorsStats[email] = user; | ||||||
|           } |           } | ||||||
| @@ -146,7 +150,7 @@ export default { | |||||||
|         user.total_additions = 0; |         user.total_additions = 0; | ||||||
|         user.total_deletions = 0; |         user.total_deletions = 0; | ||||||
|         user.max_contribution_type = 0; |         user.max_contribution_type = 0; | ||||||
|         const filteredWeeks = user.weeks.filter((week) => { |         const filteredWeeks = user.weeks.filter((week: Record<string, number>) => { | ||||||
|           const oneWeek = 7 * 24 * 60 * 60 * 1000; |           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_commits += week.commits; | ||||||
| @@ -195,7 +199,7 @@ export default { | |||||||
|       return (1 - (coefficient % 1)) * 10 ** exp + maxValue; |       return (1 - (coefficient % 1)) * 10 ** exp + maxValue; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     toGraphData(data) { |     toGraphData(data: Array<Record<string, any>>): ChartData<'line'> { | ||||||
|       return { |       return { | ||||||
|         datasets: [ |         datasets: [ | ||||||
|           { |           { | ||||||
| @@ -211,9 +215,9 @@ export default { | |||||||
|       }; |       }; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     updateOtherCharts(event, reset) { |     updateOtherCharts({chart}: {chart: Chart}, reset?: boolean = false) { | ||||||
|       const minVal = event.chart.options.scales.x.min; |       const minVal = chart.options.scales.x.min; | ||||||
|       const maxVal = event.chart.options.scales.x.max; |       const maxVal = chart.options.scales.x.max; | ||||||
|       if (reset) { |       if (reset) { | ||||||
|         this.xAxisMin = this.xAxisStart; |         this.xAxisMin = this.xAxisStart; | ||||||
|         this.xAxisMax = this.xAxisEnd; |         this.xAxisMax = this.xAxisEnd; | ||||||
| @@ -225,7 +229,7 @@ export default { | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     getOptions(type) { |     getOptions(type: string): ChartOptions<'line'> { | ||||||
|       return { |       return { | ||||||
|         responsive: true, |         responsive: true, | ||||||
|         maintainAspectRatio: false, |         maintainAspectRatio: false, | ||||||
| @@ -238,6 +242,7 @@ export default { | |||||||
|             position: 'top', |             position: 'top', | ||||||
|             align: 'center', |             align: 'center', | ||||||
|           }, |           }, | ||||||
|  |           // @ts-expect-error: bug in chart.js types | ||||||
|           customEventListener: { |           customEventListener: { | ||||||
|             chartType: type, |             chartType: type, | ||||||
|             instance: this, |             instance: this, | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import { | |||||||
|   LinearScale, |   LinearScale, | ||||||
|   TimeScale, |   TimeScale, | ||||||
|   type ChartOptions, |   type ChartOptions, | ||||||
|  |   type ChartData, | ||||||
| } from 'chart.js'; | } from 'chart.js'; | ||||||
| import {GET} from '../modules/fetch.ts'; | import {GET} from '../modules/fetch.ts'; | ||||||
| import {Bar} from 'vue-chartjs'; | import {Bar} from 'vue-chartjs'; | ||||||
| @@ -15,6 +16,7 @@ import { | |||||||
|   firstStartDateAfterDate, |   firstStartDateAfterDate, | ||||||
|   fillEmptyStartDaysWithZeroes, |   fillEmptyStartDaysWithZeroes, | ||||||
|   type DayData, |   type DayData, | ||||||
|  |   type DayDataObject, | ||||||
| } from '../utils/time.ts'; | } from '../utils/time.ts'; | ||||||
| import {chartJsColors} from '../utils/color.ts'; | import {chartJsColors} from '../utils/color.ts'; | ||||||
| import {sleep} from '../utils.ts'; | import {sleep} from '../utils.ts'; | ||||||
| @@ -61,11 +63,11 @@ async function fetchGraphData() { | |||||||
|       } |       } | ||||||
|     } while (response.status === 202); |     } while (response.status === 202); | ||||||
|     if (response.ok) { |     if (response.ok) { | ||||||
|       const data = await response.json(); |       const dayDataObj: DayDataObject = await response.json(); | ||||||
|       const start = Object.values(data)[0].week; |       const start = Object.values(dayDataObj)[0].week; | ||||||
|       const end = firstStartDateAfterDate(new Date()); |       const end = firstStartDateAfterDate(new Date()); | ||||||
|       const startDays = startDaysBetween(start, end); |       const startDays = startDaysBetween(start, end); | ||||||
|       data.value = fillEmptyStartDaysWithZeroes(startDays, data).slice(-52); |       data.value = fillEmptyStartDaysWithZeroes(startDays, dayDataObj).slice(-52); | ||||||
|       errorText.value = ''; |       errorText.value = ''; | ||||||
|     } else { |     } else { | ||||||
|       errorText.value = response.statusText; |       errorText.value = response.statusText; | ||||||
| @@ -77,10 +79,11 @@ async function fetchGraphData() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| function toGraphData(data) { | function toGraphData(data: DayData[]): ChartData<'bar'> { | ||||||
|   return { |   return { | ||||||
|     datasets: [ |     datasets: [ | ||||||
|       { |       { | ||||||
|  |         // @ts-expect-error -- bar chart expects one-dimensional data, but apparently x/y still works | ||||||
|         data: data.map((i) => ({x: i.week, y: i.commits})), |         data: data.map((i) => ({x: i.week, y: i.commits})), | ||||||
|         label: 'Commits', |         label: 'Commits', | ||||||
|         backgroundColor: chartJsColors['commits'], |         backgroundColor: chartJsColors['commits'], | ||||||
| @@ -91,10 +94,9 @@ function toGraphData(data) { | |||||||
|   }; |   }; | ||||||
| } | } | ||||||
|  |  | ||||||
| const options = { | const options: ChartOptions<'bar'> = { | ||||||
|   responsive: true, |   responsive: true, | ||||||
|   maintainAspectRatio: false, |   maintainAspectRatio: false, | ||||||
|   animation: true, |  | ||||||
|   scales: { |   scales: { | ||||||
|     x: { |     x: { | ||||||
|       type: 'time', |       type: 'time', | ||||||
|   | |||||||
| @@ -49,7 +49,11 @@ export type DayData = { | |||||||
|   commits: number, |   commits: number, | ||||||
| } | } | ||||||
|  |  | ||||||
| export function fillEmptyStartDaysWithZeroes(startDays: number[], data: DayData[]): DayData[] { | export type DayDataObject = { | ||||||
|  |   [timestamp: string]: DayData, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function fillEmptyStartDaysWithZeroes(startDays: number[], data: DayDataObject): DayData[] { | ||||||
|   const result = {}; |   const result = {}; | ||||||
|  |  | ||||||
|   for (const startDay of startDays) { |   for (const startDay of startDays) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user