初始提交: Gitea 项目代码
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
<script lang="ts" setup>
|
||||
import {SvgIcon} from '../svg.ts';
|
||||
import {
|
||||
Chart,
|
||||
Tooltip,
|
||||
BarElement,
|
||||
LinearScale,
|
||||
TimeScale,
|
||||
type ChartOptions,
|
||||
type ChartData,
|
||||
type ChartDataset,
|
||||
} 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 {errorMessage} from '../modules/errors.ts';
|
||||
import {sleep} from '../utils.ts';
|
||||
import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm';
|
||||
import {onMounted, ref, shallowRef} 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 = shallowRef(false);
|
||||
const errorText = shallowRef('');
|
||||
const repoLink = pageData.repoLink!;
|
||||
const data = ref<DayData[]>([]);
|
||||
|
||||
onMounted(() => {
|
||||
fetchGraphData();
|
||||
});
|
||||
|
||||
async function fetchGraphData() {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
let response: Response;
|
||||
do {
|
||||
response = await GET(`${repoLink}/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 = errorMessage(err);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function toGraphData(data: DayData[]): ChartData<'bar'> {
|
||||
return {
|
||||
datasets: [
|
||||
{
|
||||
data: data.map((i) => ({x: i.week, y: i.commits})),
|
||||
label: 'Commits',
|
||||
backgroundColor: chartJsColors['commits'],
|
||||
borderWidth: 0,
|
||||
tension: 0.3,
|
||||
} as unknown as ChartDataset<'bar'>,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
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">
|
||||
{{ 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="tw-m-auto">
|
||||
<div v-if="isLoading">
|
||||
<SvgIcon name="gitea-running" class="tw-mr-2 rotate-clockwise"/>
|
||||
{{ locale.loadingInfo }}
|
||||
</div>
|
||||
<div v-else class="tw-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>
|
||||
Reference in New Issue
Block a user