mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-27 00:23:41 +09:00 
			
		
		
		
	In the file tree, the icons are not vertically centered, which affects the overall visual consistency. Currently, the icons of submodules and symlinks do not adopt the value of entryIcon, resulting in inconsistent icon display. before:  after:  --------- Co-authored-by: silverwind <me@silverwind.io>
		
			
				
	
	
		
			151 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <script lang="ts" setup>
 | |
| import {SvgIcon} from '../svg.ts';
 | |
| import {
 | |
|   Chart,
 | |
|   Tooltip,
 | |
|   BarElement,
 | |
|   LinearScale,
 | |
|   TimeScale,
 | |
|   type ChartOptions,
 | |
|   type ChartData,
 | |
| } from 'chart.js';
 | |
| import {GET} from '../modules/fetch.ts';
 | |
| import {Bar} from 'vue-chartjs';
 | |
| import {
 | |
|   startDaysBetween,
 | |
|   firstStartDateAfterDate,
 | |
|   fillEmptyStartDaysWithZeroes,
 | |
|   type DayData,
 | |
|   type DayDataObject,
 | |
| } from '../utils/time.ts';
 | |
| import {chartJsColors} from '../utils/color.ts';
 | |
| import {sleep} from '../utils.ts';
 | |
| import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm';
 | |
| import {onMounted, ref} from 'vue';
 | |
| 
 | |
| const {pageData} = window.config;
 | |
| 
 | |
| Chart.defaults.color = chartJsColors.text;
 | |
| Chart.defaults.borderColor = chartJsColors.border;
 | |
| 
 | |
| Chart.register(
 | |
|   TimeScale,
 | |
|   LinearScale,
 | |
|   BarElement,
 | |
|   Tooltip,
 | |
| );
 | |
| 
 | |
| defineProps<{
 | |
|   locale: {
 | |
|     loadingTitle: string;
 | |
|     loadingTitleFailed: string;
 | |
|     loadingInfo: string;
 | |
|   };
 | |
| }>();
 | |
| 
 | |
| const isLoading = ref(false);
 | |
| const errorText = ref('');
 | |
| const repoLink = ref(pageData.repoLink || []);
 | |
| const data = ref<DayData[]>([]);
 | |
| 
 | |
| onMounted(() => {
 | |
|   fetchGraphData();
 | |
| });
 | |
| 
 | |
| async function fetchGraphData() {
 | |
|   isLoading.value = true;
 | |
|   try {
 | |
|     let response: Response;
 | |
|     do {
 | |
|       response = await GET(`${repoLink.value}/activity/recent-commits/data`);
 | |
|       if (response.status === 202) {
 | |
|         await sleep(1000); // wait for 1 second before retrying
 | |
|       }
 | |
|     } while (response.status === 202);
 | |
|     if (response.ok) {
 | |
|       const dayDataObj: DayDataObject = await response.json();
 | |
|       const start = Object.values(dayDataObj)[0].week;
 | |
|       const end = firstStartDateAfterDate(new Date());
 | |
|       const startDays = startDaysBetween(start, end);
 | |
|       data.value = fillEmptyStartDaysWithZeroes(startDays, dayDataObj).slice(-52);
 | |
|       errorText.value = '';
 | |
|     } else {
 | |
|       errorText.value = response.statusText;
 | |
|     }
 | |
|   } catch (err) {
 | |
|     errorText.value = err.message;
 | |
|   } finally {
 | |
|     isLoading.value = false;
 | |
|   }
 | |
| }
 | |
| 
 | |
| function toGraphData(data: DayData[]): ChartData<'bar'> {
 | |
|   return {
 | |
|     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})),
 | |
|         label: 'Commits',
 | |
|         backgroundColor: chartJsColors['commits'],
 | |
|         borderWidth: 0,
 | |
|         tension: 0.3,
 | |
|       },
 | |
|     ],
 | |
|   };
 | |
| }
 | |
| 
 | |
| const options: ChartOptions<'bar'> = {
 | |
|   responsive: true,
 | |
|   maintainAspectRatio: false,
 | |
|   scales: {
 | |
|     x: {
 | |
|       type: 'time',
 | |
|       grid: {
 | |
|         display: false,
 | |
|       },
 | |
|       time: {
 | |
|         minUnit: 'week',
 | |
|       },
 | |
|       ticks: {
 | |
|         maxRotation: 0,
 | |
|         maxTicksLimit: 52,
 | |
|       },
 | |
|     },
 | |
|     y: {
 | |
|       ticks: {
 | |
|         maxTicksLimit: 6,
 | |
|       },
 | |
|     },
 | |
|   },
 | |
| } satisfies ChartOptions;
 | |
| </script>
 | |
| 
 | |
| <template>
 | |
|   <div>
 | |
|     <div class="ui header tw-flex tw-items-center tw-justify-between">
 | |
|       {{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: "Number of commits in the past year" }}
 | |
|     </div>
 | |
|     <div class="tw-flex ui segment main-graph">
 | |
|       <div v-if="isLoading || errorText !== ''" class="gt-tc tw-m-auto">
 | |
|         <div v-if="isLoading">
 | |
|           <SvgIcon name="octicon-sync" class="tw-mr-2 circular-spin"/>
 | |
|           {{ locale.loadingInfo }}
 | |
|         </div>
 | |
|         <div v-else class="text red">
 | |
|           <SvgIcon name="octicon-x-circle-fill"/>
 | |
|           {{ errorText }}
 | |
|         </div>
 | |
|       </div>
 | |
|       <Bar
 | |
|         v-memo="data" v-if="data.length !== 0"
 | |
|         :data="toGraphData(data)" :options="options"
 | |
|       />
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 | |
| <style scoped>
 | |
| .main-graph {
 | |
|   height: 250px;
 | |
| }
 | |
| </style>
 |