172 lines · 4.2 KB · Vue
RawDownload
<script>import {SvgIcon} from '../svg.js';import {  Chart,  Legend,  LinearScale,  TimeScale,  PointElement,  LineElement,  Filler,} from 'chart.js';import {GET} from '../modules/fetch.js';import {Line as ChartLine} from 'vue-chartjs';import {  startDaysBetween,  firstStartDateAfterDate,  fillEmptyStartDaysWithZeroes,} from '../utils/time.js';import {chartJsColors} from '../utils/color.js';import {sleep} from '../utils.js';import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; const {pageData} = window.config; Chart.defaults.color = chartJsColors.text;Chart.defaults.borderColor = chartJsColors.border; Chart.register(  TimeScale,  LinearScale,  Legend,  PointElement,  LineElement,  Filler,); export default {  components: {ChartLine, SvgIcon},  props: {    locale: {      type: Object,      required: true,    },  },  data: () => ({    isLoading: false,    errorText: '',    repoLink: pageData.repoLink || [],    data: [],  }),  mounted() {    this.fetchGraphData();  },  methods: {    async fetchGraphData() {      this.isLoading = true;      try {        let response;        do {          response = await GET(`${this.repoLink}/activity/code-frequency/data`);          if (response.status === 202) {            await sleep(1000); // wait for 1 second before retrying          }        } while (response.status === 202);        if (response.ok) {          this.data = await response.json();          const weekValues = Object.values(this.data);          const start = weekValues[0].week;          const end = firstStartDateAfterDate(new Date());          const startDays = startDaysBetween(start, end);          this.data = fillEmptyStartDaysWithZeroes(startDays, this.data);          this.errorText = '';        } else {          this.errorText = response.statusText;        }      } catch (err) {        this.errorText = err.message;      } finally {        this.isLoading = false;      }    },     toGraphData(data) {      return {        datasets: [          {            data: data.map((i) => ({x: i.week, y: i.additions})),            pointRadius: 0,            pointHitRadius: 0,            fill: true,            label: 'Additions',            backgroundColor: chartJsColors['additions'],            borderWidth: 0,            tension: 0.3,          },          {            data: data.map((i) => ({x: i.week, y: -i.deletions})),            pointRadius: 0,            pointHitRadius: 0,            fill: true,            label: 'Deletions',            backgroundColor: chartJsColors['deletions'],            borderWidth: 0,            tension: 0.3,          },        ],      };    },     getOptions() {      return {        responsive: true,        maintainAspectRatio: false,        animation: true,        plugins: {          legend: {            display: true,          },        },        scales: {          x: {            type: 'time',            grid: {              display: false,            },            time: {              minUnit: 'month',            },            ticks: {              maxRotation: 0,              maxTicksLimit: 12,            },          },          y: {            ticks: {              maxTicksLimit: 6,            },          },        },      };    },  },};</script><template>  <div>    <div class="ui header tw-flex tw-items-center tw-justify-between">      {{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: `Code frequency over the history of ${repoLink.slice(1)}` }}    </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 job-status-rotate"/>          {{ locale.loadingInfo }}        </div>        <div v-else class="text red">          <SvgIcon name="octicon-x-circle-fill"/>          {{ errorText }}        </div>      </div>      <ChartLine        v-memo="data" v-if="data.length !== 0"        :data="toGraphData(data)" :options="getOptions()"      />    </div>  </div></template><style scoped>.main-graph {  height: 440px;}</style>