Skip to content

Commit 8aad900

Browse files
committed
feature: added display of intervals
1 parent b8c3dcb commit 8aad900

File tree

1 file changed

+59
-42
lines changed

1 file changed

+59
-42
lines changed

git_analytics/static/js/git-analytics.js

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
function formatDate(d) {
1+
const CHARTS = Object.create(null);
2+
3+
function toISODate(d) {
24
const y = d.getFullYear();
35
const m = String(d.getMonth() + 1).padStart(2, "0");
46
const day = String(d.getDate()).padStart(2, "0");
57
return `${y}-${m}-${day}`;
68
}
79

8-
function subtractMonths(date, n) {
10+
function subMonths(date, n) {
911
const d = new Date(date);
1012
const origDay = d.getDate();
1113
d.setDate(1);
@@ -15,36 +17,43 @@ function subtractMonths(date, n) {
1517
return d;
1618
}
1719

18-
function buildQueryForRange(range) {
19-
if (range === 'all') return '';
20+
function computeRange(type, value) {
21+
if (type === "all") return null;
2022

21-
const days = Number(range);
22-
const now = new Date();
23-
const stop = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
24-
const start = new Date(stop);
25-
start.setUTCDate(start.getUTCDate() - days);
23+
const today = new Date();
24+
let start, stop;
2625

27-
const params = new URLSearchParams({
28-
start_date: formatDateUTC_YYYYMMDD(start),
29-
stop_date: formatDateUTC_YYYYMMDD(stop),
30-
});
31-
return `?${params.toString()}`;
26+
if (type === "days") {
27+
stop = today;
28+
start = new Date(today);
29+
start.setDate(start.getDate() - Number(value));
30+
} else if (type === "months") {
31+
stop = today;
32+
start = subMonths(today, Number(value));
33+
}
34+
35+
return { start: toISODate(start), stop: toISODate(stop) };
3236
}
3337

34-
async function fetchStatisticsWithRange(range) {
35-
const qs = buildQueryForRange(range);
36-
const res = await fetch(`/api/statistics${qs}`);
37-
if (!res.ok) throw new Error('Failed to fetch /api/statistics');
38-
return await res.json();
38+
async function fetchStatistics(type, value) {
39+
const range = computeRange(type, value);
40+
let url = "/api/statistics";
41+
if (range) {
42+
url += `?start_date=${range.start}&stop_date=${range.stop}`;
43+
}
44+
const res = await fetch(url);
45+
if (!res.ok) throw new Error("Failed to fetch statistics");
46+
const data = await res.json();
47+
return data;
3948
}
4049

41-
async function loadAndRender(range) {
50+
async function loadAndRender(type, value) {
4251
try {
4352
// fetch stats
4453
const modalEl = document.getElementById("loadingModal");
4554
const modal = new bootstrap.Modal(modalEl, { backdrop: "static", keyboard: false });
4655
modal.show();
47-
const stats = await fetchStatisticsWithRange(range);
56+
const stats = await fetchStatistics(type, value);
4857
modal.hide();
4958

5059
// render stats
@@ -80,13 +89,21 @@ function renderSummary(stats) {
8089
`;
8190
}
8291

92+
function renderChart(id, config) {
93+
if (CHARTS[id]) {
94+
CHARTS[id].destroy();
95+
}
96+
const ctx = document.getElementById(id).getContext("2d");
97+
CHARTS[id] = new Chart(ctx, config);
98+
}
99+
83100
function buildAuthorsChart(authorsData) {
84101
const labels = Object.keys(authorsData);
85102
const dataValues = Object.values(authorsData).map(a => a.commits);
86103

87104
const ctx = document.getElementById("chartAuthors").getContext("2d");
88105

89-
new Chart(ctx, {
106+
renderChart("chartAuthors", {
90107
type: "pie",
91108
data: {
92109
labels: labels,
@@ -109,7 +126,7 @@ function buildAuthorsStackedChart(authorsData) {
109126

110127
const ctx = document.getElementById("chartAuthors2").getContext("2d");
111128

112-
new Chart(ctx, {
129+
renderChart("chartAuthors2", {
113130
type: "bar",
114131
data: {
115132
labels,
@@ -172,7 +189,8 @@ function buildHourByAuthorChart(hourOfDayData) {
172189

173190
if (authors.size === 0) {
174191
const totals = HOUR_LABELS.map(h => hourOfDayData[h] ?? 0);
175-
new Chart(ctx, {
192+
193+
renderChart("chartDay", {
176194
type: "bar",
177195
data: { labels: HOUR_LABELS, datasets: [{ label: "Total", data: totals, stack: "commits", borderWidth: 1 }] },
178196
options: {
@@ -198,7 +216,7 @@ function buildHourByAuthorChart(hourOfDayData) {
198216
borderWidth: 1
199217
}));
200218

201-
new Chart(ctx, {
219+
renderChart("chartDay", {
202220
type: "bar",
203221
data: { labels: HOUR_LABELS, datasets },
204222
options: {
@@ -231,7 +249,7 @@ function buildWeekByAuthorChart(dayOfWeekData) {
231249

232250
if (authors.size === 0) {
233251
const totals = WEEK_LABELS.map(d => dayOfWeekData[d] ?? 0);
234-
new Chart(ctx, {
252+
renderChart("chartWeek", {
235253
type: "bar",
236254
data: {
237255
labels: WEEK_LABELS,
@@ -259,7 +277,7 @@ function buildWeekByAuthorChart(dayOfWeekData) {
259277
stack: "commits"
260278
}));
261279

262-
new Chart(ctx, {
280+
renderChart("chartWeek", {
263281
type: "bar",
264282
data: { labels: WEEK_LABELS, datasets },
265283
options: {
@@ -292,7 +310,7 @@ function buildDayOfMonthByAuthorChart(dayOfMonthData) {
292310

293311
if (authors.size === 0) {
294312
const totals = DAY_LABELS.map(d => dayOfMonthData[d] ?? 0);
295-
new Chart(ctx, {
313+
renderChart("chartMonth", {
296314
type: "bar",
297315
data: { labels: DAY_LABELS, datasets: [{ label: "Total", data: totals, stack: "commits", borderWidth: 1 }] },
298316
options: {
@@ -320,7 +338,7 @@ function buildDayOfMonthByAuthorChart(dayOfMonthData) {
320338
borderWidth: 1
321339
}));
322340

323-
new Chart(ctx, {
341+
renderChart("chartMonth", {
324342
type: "bar",
325343
data: { labels: DAY_LABELS, datasets },
326344
options: {
@@ -348,7 +366,7 @@ function buildLinesChart(linesItems) {
348366

349367
const ctx = document.getElementById("chartLines").getContext("2d");
350368

351-
new Chart(ctx, {
369+
renderChart("chartLines", {
352370
type: "line",
353371
data: {
354372
labels,
@@ -401,7 +419,7 @@ function buildCommitTypeChart(commitTypeData) {
401419
stack: "commitTypes"
402420
}));
403421

404-
new Chart(ctx, {
422+
renderChart("typesCommits", {
405423
type: "bar",
406424
data: {
407425
labels: dates,
@@ -448,20 +466,19 @@ function buildAuthorsTable(authorsData) {
448466
}
449467

450468
// start
451-
document.addEventListener('DOMContentLoaded', () => {
452-
const menu = document.getElementById('rangeMenu');
453-
const btn = document.getElementById('rangeDropdownBtn');
469+
document.addEventListener("DOMContentLoaded", () => {
470+
const menu = document.getElementById("rangeMenu");
471+
const btn = document.getElementById("rangeDropdownBtn");
454472

455-
const DEFAULT_RANGE = '30';
456-
loadAndRender(DEFAULT_RANGE);
473+
loadAndRender("months", 1);
457474

458-
menu.addEventListener('click', (e) => {
459-
const item = e.target.closest('.dropdown-item');
475+
menu.addEventListener("click", (e) => {
476+
const item = e.target.closest(".dropdown-item");
460477
if (!item) return;
461478
e.preventDefault();
462-
463-
const range = item.dataset.range;
464-
btn.textContent = item.textContent;
465-
loadAndRender(range);
479+
const type = item.dataset.type;
480+
const value = item.dataset.value;
481+
btn.textContent = item.textContent.trim();
482+
loadAndRender(type, value);
466483
});
467484
});

0 commit comments

Comments
 (0)