2024-10-28 21:15:05 +01:00
|
|
|
<script lang="ts" setup>
|
2024-07-07 17:32:30 +02:00
|
|
|
import {SvgIcon} from '../svg.ts';
|
2024-02-24 11:22:51 +01:00
|
|
|
import {
|
|
|
|
Chart,
|
|
|
|
Tooltip,
|
|
|
|
BarElement,
|
|
|
|
LinearScale,
|
|
|
|
TimeScale,
|
2024-10-28 21:15:05 +01:00
|
|
|
type ChartOptions,
|
2024-02-24 11:22:51 +01:00
|
|
|
} from 'chart.js';
|
2024-07-07 17:32:30 +02:00
|
|
|
import {GET} from '../modules/fetch.ts';
|
2024-02-24 11:22:51 +01:00
|
|
|
import {Bar} from 'vue-chartjs';
|
|
|
|
import {
|
|
|
|
startDaysBetween,
|
|
|
|
firstStartDateAfterDate,
|
|
|
|
fillEmptyStartDaysWithZeroes,
|
2024-10-28 21:15:05 +01:00
|
|
|
type DayData,
|
2024-07-07 17:32:30 +02:00
|
|
|
} from '../utils/time.ts';
|
|
|
|
import {chartJsColors} from '../utils/color.ts';
|
|
|
|
import {sleep} from '../utils.ts';
|
2024-02-24 11:22:51 +01:00
|
|
|
import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm';
|
2024-10-28 21:15:05 +01:00
|
|
|
import {onMounted, ref} from 'vue';
|
2024-02-24 11:22:51 +01:00
|
|
|
|
|
|
|
const {pageData} = window.config;
|
|
|
|
|
|
|
|
Chart.defaults.color = chartJsColors.text;
|
|
|
|
Chart.defaults.borderColor = chartJsColors.border;
|
|
|
|
|
|
|
|
Chart.register(
|
|
|
|
TimeScale,
|
|
|
|
LinearScale,
|
|
|
|
BarElement,
|
|
|
|
Tooltip,
|
|
|
|
);
|
|
|
|
|
2024-10-28 21:15:05 +01:00
|
|
|
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
|
2024-02-24 11:22:51 +01:00
|
|
|
}
|
2024-10-28 21:15:05 +01:00
|
|
|
} while (response.status === 202);
|
|
|
|
if (response.ok) {
|
|
|
|
const data = await response.json();
|
|
|
|
const start = Object.values(data)[0].week;
|
|
|
|
const end = firstStartDateAfterDate(new Date());
|
|
|
|
const startDays = startDaysBetween(start, end);
|
|
|
|
data.value = fillEmptyStartDaysWithZeroes(startDays, data).slice(-52);
|
|
|
|
errorText.value = '';
|
|
|
|
} else {
|
|
|
|
errorText.value = response.statusText;
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
errorText.value = err.message;
|
|
|
|
} finally {
|
|
|
|
isLoading.value = false;
|
|
|
|
}
|
|
|
|
}
|
2024-02-24 11:22:51 +01:00
|
|
|
|
2024-10-28 21:15:05 +01:00
|
|
|
function toGraphData(data) {
|
|
|
|
return {
|
|
|
|
datasets: [
|
|
|
|
{
|
|
|
|
data: data.map((i) => ({x: i.week, y: i.commits})),
|
|
|
|
label: 'Commits',
|
|
|
|
backgroundColor: chartJsColors['commits'],
|
|
|
|
borderWidth: 0,
|
|
|
|
tension: 0.3,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
};
|
|
|
|
}
|
2024-02-24 11:22:51 +01:00
|
|
|
|
2024-10-28 21:15:05 +01:00
|
|
|
const options = {
|
|
|
|
responsive: true,
|
|
|
|
maintainAspectRatio: false,
|
|
|
|
animation: true,
|
|
|
|
scales: {
|
|
|
|
x: {
|
|
|
|
type: 'time',
|
|
|
|
grid: {
|
|
|
|
display: false,
|
|
|
|
},
|
|
|
|
time: {
|
|
|
|
minUnit: 'week',
|
|
|
|
},
|
|
|
|
ticks: {
|
|
|
|
maxRotation: 0,
|
|
|
|
maxTicksLimit: 52,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
y: {
|
|
|
|
ticks: {
|
|
|
|
maxTicksLimit: 6,
|
|
|
|
},
|
2024-02-24 11:22:51 +01:00
|
|
|
},
|
|
|
|
},
|
2024-10-28 21:15:05 +01:00
|
|
|
} satisfies ChartOptions;
|
2024-02-24 11:22:51 +01:00
|
|
|
</script>
|
2024-10-28 21:15:05 +01:00
|
|
|
|
2024-02-24 11:22:51 +01:00
|
|
|
<template>
|
|
|
|
<div>
|
2024-03-22 20:51:29 +01:00
|
|
|
<div class="ui header tw-flex tw-items-center tw-justify-between">
|
2024-02-24 11:22:51 +01:00
|
|
|
{{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: "Number of commits in the past year" }}
|
|
|
|
</div>
|
2024-03-22 14:45:10 +01:00
|
|
|
<div class="tw-flex ui segment main-graph">
|
2024-03-18 15:47:05 +01:00
|
|
|
<div v-if="isLoading || errorText !== ''" class="gt-tc tw-m-auto">
|
2024-02-24 11:22:51 +01:00
|
|
|
<div v-if="isLoading">
|
Migrate margin and padding helpers to tailwind (#30043)
This will conclude the refactor of 1:1 class replacements to tailwind,
except `gt-hidden`. Commands ran:
```bash
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-0#tw-$1$2-0#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-1#tw-$1$2-0.5#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-2#tw-$1$2-1#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-3#tw-$1$2-2#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-4#tw-$1$2-4#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-5#tw-$1$2-8#g' {web_src/js,templates,routers,services}/**/*
```
2024-03-24 17:42:49 +01:00
|
|
|
<SvgIcon name="octicon-sync" class="tw-mr-2 job-status-rotate"/>
|
2024-02-24 11:22:51 +01:00
|
|
|
{{ 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"
|
2024-10-28 21:15:05 +01:00
|
|
|
:data="toGraphData(data)" :options="options"
|
2024-02-24 11:22:51 +01:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<style scoped>
|
|
|
|
.main-graph {
|
|
|
|
height: 250px;
|
|
|
|
}
|
|
|
|
</style>
|