loading up the forgejo repo on tangled to test page performance
at forgejo 172 lines 4.3 kB view raw
1<script> 2import {SvgIcon} from '../svg.js'; 3import { 4 Chart, 5 Legend, 6 LinearScale, 7 TimeScale, 8 PointElement, 9 LineElement, 10 Filler, 11} from 'chart.js'; 12import {GET} from '../modules/fetch.js'; 13import {Line as ChartLine} from 'vue-chartjs'; 14import { 15 startDaysBetween, 16 firstStartDateAfterDate, 17 fillEmptyStartDaysWithZeroes, 18} from '../utils/time.js'; 19import {chartJsColors} from '../utils/color.js'; 20import {sleep} from '../utils.js'; 21import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; 22 23const {pageData} = window.config; 24 25Chart.defaults.color = chartJsColors.text; 26Chart.defaults.borderColor = chartJsColors.border; 27 28Chart.register( 29 TimeScale, 30 LinearScale, 31 Legend, 32 PointElement, 33 LineElement, 34 Filler, 35); 36 37export default { 38 components: {ChartLine, SvgIcon}, 39 props: { 40 locale: { 41 type: Object, 42 required: true, 43 }, 44 }, 45 data: () => ({ 46 isLoading: false, 47 errorText: '', 48 repoLink: pageData.repoLink || [], 49 data: [], 50 }), 51 mounted() { 52 this.fetchGraphData(); 53 }, 54 methods: { 55 async fetchGraphData() { 56 this.isLoading = true; 57 try { 58 let response; 59 do { 60 response = await GET(`${this.repoLink}/activity/code-frequency/data`); 61 if (response.status === 202) { 62 await sleep(1000); // wait for 1 second before retrying 63 } 64 } while (response.status === 202); 65 if (response.ok) { 66 this.data = await response.json(); 67 const weekValues = Object.values(this.data); 68 const start = weekValues[0].week; 69 const end = firstStartDateAfterDate(new Date()); 70 const startDays = startDaysBetween(start, end); 71 this.data = fillEmptyStartDaysWithZeroes(startDays, this.data); 72 this.errorText = ''; 73 } else { 74 this.errorText = response.statusText; 75 } 76 } catch (err) { 77 this.errorText = err.message; 78 } finally { 79 this.isLoading = false; 80 } 81 }, 82 83 toGraphData(data) { 84 return { 85 datasets: [ 86 { 87 data: data.map((i) => ({x: i.week, y: i.additions})), 88 pointRadius: 0, 89 pointHitRadius: 0, 90 fill: true, 91 label: 'Additions', 92 backgroundColor: chartJsColors['additions'], 93 borderWidth: 0, 94 tension: 0.3, 95 }, 96 { 97 data: data.map((i) => ({x: i.week, y: -i.deletions})), 98 pointRadius: 0, 99 pointHitRadius: 0, 100 fill: true, 101 label: 'Deletions', 102 backgroundColor: chartJsColors['deletions'], 103 borderWidth: 0, 104 tension: 0.3, 105 }, 106 ], 107 }; 108 }, 109 110 getOptions() { 111 return { 112 responsive: true, 113 maintainAspectRatio: false, 114 animation: true, 115 plugins: { 116 legend: { 117 display: true, 118 }, 119 }, 120 scales: { 121 x: { 122 type: 'time', 123 grid: { 124 display: false, 125 }, 126 time: { 127 minUnit: 'month', 128 }, 129 ticks: { 130 maxRotation: 0, 131 maxTicksLimit: 12, 132 }, 133 }, 134 y: { 135 ticks: { 136 maxTicksLimit: 6, 137 }, 138 }, 139 }, 140 }; 141 }, 142 }, 143}; 144</script> 145<template> 146 <div> 147 <div class="ui header tw-flex tw-items-center tw-justify-between"> 148 {{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: `Code frequency over the history of ${repoLink.slice(1)}` }} 149 </div> 150 <div class="tw-flex ui segment main-graph"> 151 <div v-if="isLoading || errorText !== ''" class="gt-tc tw-m-auto"> 152 <div v-if="isLoading"> 153 <SvgIcon name="octicon-sync" class="tw-mr-2 job-status-rotate"/> 154 {{ locale.loadingInfo }} 155 </div> 156 <div v-else class="text red"> 157 <SvgIcon name="octicon-x-circle-fill"/> 158 {{ errorText }} 159 </div> 160 </div> 161 <ChartLine 162 v-memo="data" v-if="data.length !== 0" 163 :data="toGraphData(data)" :options="getOptions()" 164 /> 165 </div> 166 </div> 167</template> 168<style scoped> 169.main-graph { 170 height: 440px; 171} 172</style>