Update from Git Manager GUI

This commit is contained in:
2026-03-24 19:18:28 +01:00
parent b2ba2a09e2
commit 0f758616cf

View File

@@ -260,6 +260,144 @@ async function listGiteaRepos({ token, url }) {
return response.data;
}
function toDateKey(value) {
if (value == null) return null;
if (typeof value === 'string') {
const s = value.trim();
if (!s) return null;
const match = s.match(/^(\d{4}-\d{2}-\d{2})/);
if (match) return match[1];
if (/^\d+$/.test(s)) {
const n = Number(s);
if (!Number.isFinite(n)) return null;
const ms = n < 1e12 ? n * 1000 : n;
const d = new Date(ms);
if (Number.isNaN(d.getTime())) return null;
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
}
const d = new Date(s);
if (Number.isNaN(d.getTime())) return null;
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
}
if (typeof value === 'number' && Number.isFinite(value)) {
const ms = value < 1e12 ? value * 1000 : value;
const d = new Date(ms);
if (Number.isNaN(d.getTime())) return null;
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
}
if (value instanceof Date && !Number.isNaN(value.getTime())) {
return `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, '0')}-${String(value.getDate()).padStart(2, '0')}`;
}
return null;
}
function normalizeHeatmapEntries(payload) {
const acc = new Map();
const addEntry = (dateLike, countLike) => {
const key = toDateKey(dateLike);
if (!key) return;
const n = Number(countLike);
const count = Number.isFinite(n) ? Math.max(0, Math.floor(n)) : 1;
acc.set(key, (acc.get(key) || 0) + count);
};
const walk = (node, depth = 0) => {
if (depth > 6 || node == null) return;
if (Array.isArray(node)) {
node.forEach(item => walk(item, depth + 1));
return;
}
if (typeof node === 'number' || typeof node === 'string' || node instanceof Date) {
addEntry(node, 1);
return;
}
if (typeof node !== 'object') return;
const dateLike =
node.date ?? node.day ?? node.timestamp ?? node.time ?? node.ts ?? node.created_at ?? node.created ?? node.when;
const countLike =
node.count ?? node.contributions ?? node.value ?? node.total ?? node.commits ?? node.frequency;
if (dateLike != null) {
addEntry(dateLike, countLike);
}
if (node.data != null) walk(node.data, depth + 1);
if (node.values != null) walk(node.values, depth + 1);
if (node.heatmap != null) walk(node.heatmap, depth + 1);
if (node.contributions != null) walk(node.contributions, depth + 1);
if (node.days != null) walk(node.days, depth + 1);
const keys = Object.keys(node);
for (const key of keys) {
if (/^\d{4}-\d{2}-\d{2}$/.test(key)) {
addEntry(key, node[key]);
}
}
};
walk(payload, 0);
return Array.from(acc.entries())
.map(([date, count]) => ({ date, count }))
.sort((a, b) => a.date.localeCompare(b.date));
}
async function getGiteaUserHeatmap({ token, url }) {
const base = normalizeBase(url);
if (!base) throw new Error('Invalid Gitea base URL');
const headers = {
Authorization: `token ${token}`,
'User-Agent': 'Git-Manager-GUI'
};
const meRes = await axiosInstance.get(`${base}/api/v1/user`, {
headers,
timeout: 10000
});
const username = meRes?.data?.login || meRes?.data?.username || meRes?.data?.name || null;
const candidates = [
`${base}/api/v1/user/heatmap`,
username ? `${base}/api/v1/users/${encodeURIComponent(username)}/heatmap` : null
].filter(Boolean);
let lastError = null;
for (const endpoint of candidates) {
try {
const response = await axiosInstance.get(endpoint, {
headers,
timeout: 12000,
validateStatus: () => true
});
if (response.status >= 200 && response.status < 300) {
return {
username,
endpoint,
entries: normalizeHeatmapEntries(response.data)
};
}
lastError = new Error(`Heatmap endpoint failed (${response.status}): ${endpoint}`);
} catch (e) {
lastError = e;
}
}
throw lastError || new Error('No usable heatmap endpoint found');
}
/**
* Returns array of items for a directory or single item for file.
* Each item includes name, path, type, size, download_url, sha (if present).
@@ -926,6 +1064,7 @@ module.exports = {
createRepoGitea,
checkGiteaConnection,
listGiteaRepos,
getGiteaUserHeatmap,
getGiteaRepoContents,
getGiteaFileContent,
uploadGiteaFile,