feat: 生成/审查页面的 ref 选择器添加标签和最近提交
This commit is contained in:
@@ -13,13 +13,13 @@
|
|||||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
||||||
<div class="grid grid-cols-2 gap-4 mb-4">
|
<div class="grid grid-cols-2 gap-4 mb-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">Base 分支</label>
|
<label class="block text-sm font-medium text-gray-700 mb-1">Base</label>
|
||||||
<select id="base-ref" class="w-full border rounded-md px-3 py-2" required>
|
<select id="base-ref" class="w-full border rounded-md px-3 py-2" required>
|
||||||
<option value="">加载中...</option>
|
<option value="">加载中...</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">Head 分支</label>
|
<label class="block text-sm font-medium text-gray-700 mb-1">Head</label>
|
||||||
<select id="head-ref" class="w-full border rounded-md px-3 py-2" required>
|
<select id="head-ref" class="w-full border rounded-md px-3 py-2" required>
|
||||||
<option value="">加载中...</option>
|
<option value="">加载中...</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -94,40 +94,82 @@
|
|||||||
if (!resp.ok) throw new Error('Failed to load refs');
|
if (!resp.ok) throw new Error('Failed to load refs');
|
||||||
const refs = await resp.json();
|
const refs = await resp.json();
|
||||||
|
|
||||||
const baseSelect = document.getElementById('base-ref');
|
// Fetch recent commits for the "Recent Commits" group
|
||||||
const headSelect = document.getElementById('head-ref');
|
let commits = [];
|
||||||
baseSelect.innerHTML = '<option value="">选择分支</option>';
|
try {
|
||||||
headSelect.innerHTML = '<option value="">选择分支</option>';
|
const graphResp = await fetch(`/api/repos/${repoId}/graph?max_commits=20`);
|
||||||
|
if (graphResp.ok) {
|
||||||
|
commits = await graphResp.json();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to load recent commits:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
const selects = ['base-ref', 'head-ref'];
|
||||||
const branches = refs.filter(r => !r.is_tag);
|
const branches = refs.filter(r => !r.is_tag);
|
||||||
|
const tags = refs.filter(r => r.is_tag);
|
||||||
|
|
||||||
branches.forEach(ref => {
|
selects.forEach(selectId => {
|
||||||
const opt1 = document.createElement('option');
|
const select = document.getElementById(selectId);
|
||||||
opt1.value = ref.name;
|
select.innerHTML = '<option value="">选择分支/标签</option>';
|
||||||
opt1.textContent = ref.name + (ref.is_head ? ' (HEAD)' : '');
|
|
||||||
baseSelect.appendChild(opt1);
|
|
||||||
|
|
||||||
const opt2 = document.createElement('option');
|
if (branches.length > 0) {
|
||||||
opt2.value = ref.name;
|
const group = document.createElement('optgroup');
|
||||||
opt2.textContent = ref.name + (ref.is_head ? ' (HEAD)' : '');
|
group.label = '分支';
|
||||||
headSelect.appendChild(opt2);
|
branches.forEach(ref => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = ref.name;
|
||||||
|
opt.textContent = ref.name + (ref.is_head ? ' (HEAD)' : '');
|
||||||
|
group.appendChild(opt);
|
||||||
|
});
|
||||||
|
select.appendChild(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags.length > 0) {
|
||||||
|
const group = document.createElement('optgroup');
|
||||||
|
group.label = '标签';
|
||||||
|
tags.forEach(ref => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = ref.name;
|
||||||
|
opt.textContent = ref.name;
|
||||||
|
group.appendChild(opt);
|
||||||
|
});
|
||||||
|
select.appendChild(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commits.length > 0) {
|
||||||
|
const group = document.createElement('optgroup');
|
||||||
|
group.label = '最近提交';
|
||||||
|
commits.forEach(commit => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = commit.hash;
|
||||||
|
opt.textContent = `${commit.short_hash} ${commit.message.substring(0, 40)}`;
|
||||||
|
group.appendChild(opt);
|
||||||
|
});
|
||||||
|
select.appendChild(group);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auto-select from URL params, or fall back to main/master and HEAD
|
// Auto-select from URL params, or fall back to main/master and HEAD
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const urlBase = params.get('base');
|
const urlBase = params.get('base');
|
||||||
const urlHead = params.get('head');
|
const urlHead = params.get('head');
|
||||||
|
const baseSelect = document.getElementById('base-ref');
|
||||||
|
const headSelect = document.getElementById('head-ref');
|
||||||
|
|
||||||
const mainBranch = branches.find(b => b.name === 'main' || b.name === 'master');
|
const mainBranch = branches.find(b => b.name === 'main' || b.name === 'master');
|
||||||
const headBranch = branches.find(r => r.is_head);
|
const headBranch = refs.find(r => r.is_head);
|
||||||
|
|
||||||
if (urlBase && branches.some(b => b.name === urlBase)) {
|
// Check if value exists in select options
|
||||||
|
const hasOption = (select, val) => Array.from(select.options).some(o => o.value === val);
|
||||||
|
|
||||||
|
if (urlBase && hasOption(baseSelect, urlBase)) {
|
||||||
baseSelect.value = urlBase;
|
baseSelect.value = urlBase;
|
||||||
} else if (mainBranch) {
|
} else if (mainBranch) {
|
||||||
baseSelect.value = mainBranch.name;
|
baseSelect.value = mainBranch.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (urlHead && branches.some(b => b.name === urlHead)) {
|
if (urlHead && hasOption(headSelect, urlHead)) {
|
||||||
headSelect.value = urlHead;
|
headSelect.value = urlHead;
|
||||||
} else if (headBranch) {
|
} else if (headBranch) {
|
||||||
headSelect.value = headBranch.name;
|
headSelect.value = headBranch.name;
|
||||||
|
|||||||
+74
-19
@@ -19,13 +19,13 @@
|
|||||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
||||||
<div class="grid grid-cols-3 gap-4 mb-4">
|
<div class="grid grid-cols-3 gap-4 mb-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">Base 分支</label>
|
<label class="block text-sm font-medium text-gray-700 mb-1">Base</label>
|
||||||
<select id="base-ref" class="w-full border rounded-md px-3 py-2" required>
|
<select id="base-ref" class="w-full border rounded-md px-3 py-2" required>
|
||||||
<option value="">加载中...</option>
|
<option value="">加载中...</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">Head 分支</label>
|
<label class="block text-sm font-medium text-gray-700 mb-1">Head</label>
|
||||||
<select id="head-ref" class="w-full border rounded-md px-3 py-2" required>
|
<select id="head-ref" class="w-full border rounded-md px-3 py-2" required>
|
||||||
<option value="">加载中...</option>
|
<option value="">加载中...</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -115,30 +115,85 @@
|
|||||||
if (!resp.ok) throw new Error('Failed to load refs');
|
if (!resp.ok) throw new Error('Failed to load refs');
|
||||||
const refs = await resp.json();
|
const refs = await resp.json();
|
||||||
|
|
||||||
const baseSelect = document.getElementById('base-ref');
|
// Fetch recent commits for the "Recent Commits" group
|
||||||
const headSelect = document.getElementById('head-ref');
|
let commits = [];
|
||||||
baseSelect.innerHTML = '<option value="">选择分支</option>';
|
try {
|
||||||
headSelect.innerHTML = '<option value="">选择分支</option>';
|
const graphResp = await fetch(`/api/repos/${repoId}/graph?max_commits=20`);
|
||||||
|
if (graphResp.ok) {
|
||||||
|
commits = await graphResp.json();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to load recent commits:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
const selects = ['base-ref', 'head-ref'];
|
||||||
const branches = refs.filter(r => !r.is_tag);
|
const branches = refs.filter(r => !r.is_tag);
|
||||||
|
const tags = refs.filter(r => r.is_tag);
|
||||||
|
|
||||||
branches.forEach(ref => {
|
selects.forEach(selectId => {
|
||||||
const opt1 = document.createElement('option');
|
const select = document.getElementById(selectId);
|
||||||
opt1.value = ref.name;
|
select.innerHTML = '<option value="">选择分支/标签</option>';
|
||||||
opt1.textContent = ref.name + (ref.is_head ? ' (HEAD)' : '');
|
|
||||||
baseSelect.appendChild(opt1);
|
|
||||||
|
|
||||||
const opt2 = document.createElement('option');
|
if (branches.length > 0) {
|
||||||
opt2.value = ref.name;
|
const group = document.createElement('optgroup');
|
||||||
opt2.textContent = ref.name + (ref.is_head ? ' (HEAD)' : '');
|
group.label = '分支';
|
||||||
headSelect.appendChild(opt2);
|
branches.forEach(ref => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = ref.name;
|
||||||
|
opt.textContent = ref.name + (ref.is_head ? ' (HEAD)' : '');
|
||||||
|
group.appendChild(opt);
|
||||||
|
});
|
||||||
|
select.appendChild(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags.length > 0) {
|
||||||
|
const group = document.createElement('optgroup');
|
||||||
|
group.label = '标签';
|
||||||
|
tags.forEach(ref => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = ref.name;
|
||||||
|
opt.textContent = ref.name;
|
||||||
|
group.appendChild(opt);
|
||||||
|
});
|
||||||
|
select.appendChild(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commits.length > 0) {
|
||||||
|
const group = document.createElement('optgroup');
|
||||||
|
group.label = '最近提交';
|
||||||
|
commits.forEach(commit => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = commit.hash;
|
||||||
|
opt.textContent = `${commit.short_hash} ${commit.message.substring(0, 40)}`;
|
||||||
|
group.appendChild(opt);
|
||||||
|
});
|
||||||
|
select.appendChild(group);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const mainBranch = branches.find(b => b.name === 'main' || b.name === 'master');
|
// Auto-select from URL params, or fall back to main/master and HEAD
|
||||||
const headBranch = branches.find(r => r.is_head);
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const urlBase = params.get('base');
|
||||||
|
const urlHead = params.get('head');
|
||||||
|
const baseSelect = document.getElementById('base-ref');
|
||||||
|
const headSelect = document.getElementById('head-ref');
|
||||||
|
|
||||||
if (mainBranch) baseSelect.value = mainBranch.name;
|
const mainBranch = branches.find(b => b.name === 'main' || b.name === 'master');
|
||||||
if (headBranch) headSelect.value = headBranch.name;
|
const headBranch = refs.find(r => r.is_head);
|
||||||
|
|
||||||
|
const hasOption = (select, val) => Array.from(select.options).some(o => o.value === val);
|
||||||
|
|
||||||
|
if (urlBase && hasOption(baseSelect, urlBase)) {
|
||||||
|
baseSelect.value = urlBase;
|
||||||
|
} else if (mainBranch) {
|
||||||
|
baseSelect.value = mainBranch.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urlHead && hasOption(headSelect, urlHead)) {
|
||||||
|
headSelect.value = urlHead;
|
||||||
|
} else if (headBranch) {
|
||||||
|
headSelect.value = headBranch.name;
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Load refs error:', err);
|
console.error('Load refs error:', err);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user