feat(chronicle): 設定パネルに GitHub PAT 欄を追加、ブラウザ直接 GitHub API 接続に変更
This commit is contained in:
parent
e5df1c0240
commit
ffc144fd31
98
index.html
98
index.html
|
|
@ -180,7 +180,23 @@
|
|||
</button>
|
||||
</div>
|
||||
<div class="settings-panel-body">
|
||||
<div class="settings-group-label">外観</div>
|
||||
<div class="settings-group-label">GitHub 連携</div>
|
||||
<div class="settings-item" style="flex-direction:column;align-items:flex-start;gap:6px">
|
||||
<div class="settings-item-label">Personal Access Token</div>
|
||||
<div style="font-size:11px;color:var(--text3);line-height:1.5">
|
||||
github.com → Settings → Developer settings<br>
|
||||
→ Fine-grained tokens → Generate new token<br>
|
||||
Permissions: <strong style="color:var(--text2)">Contents: Read-only</strong>
|
||||
</div>
|
||||
<div style="display:flex;gap:6px;width:100%">
|
||||
<input type="password" id="ghPatInput" placeholder="github_pat_..." autocomplete="off"
|
||||
style="flex:1;background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-family:inherit;font-size:12px;padding:7px 10px;min-width:0">
|
||||
<button class="btn btn-ghost" id="ghPatSaveBtn" style="font-size:12px;padding:6px 12px;flex-shrink:0">保存</button>
|
||||
</div>
|
||||
<div id="ghPatStatus" style="font-size:11px;color:var(--text3)"></div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group-label" style="margin-top:16px">外観</div>
|
||||
<div class="settings-item">
|
||||
<div class="settings-item-label">テーマ</div>
|
||||
<div class="theme-selector">
|
||||
|
|
@ -487,47 +503,85 @@ document.getElementById('copyBtn').addEventListener('click', async () => {
|
|||
}
|
||||
});
|
||||
|
||||
// ── GitHub PAT 設定 ───────────────────
|
||||
const GH_PAT_KEY = 'posimai-chronicle-gh-pat';
|
||||
function getGhPat() { return localStorage.getItem(GH_PAT_KEY) || ''; }
|
||||
|
||||
(function initGhPatUI() {
|
||||
const input = document.getElementById('ghPatInput');
|
||||
const status = document.getElementById('ghPatStatus');
|
||||
const pat = getGhPat();
|
||||
if (pat) {
|
||||
input.value = pat;
|
||||
status.textContent = '設定済み';
|
||||
status.style.color = 'var(--accent)';
|
||||
}
|
||||
document.getElementById('ghPatSaveBtn').addEventListener('click', () => {
|
||||
const val = input.value.trim();
|
||||
if (!val) {
|
||||
localStorage.removeItem(GH_PAT_KEY);
|
||||
status.textContent = '削除しました';
|
||||
status.style.color = 'var(--text3)';
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(GH_PAT_KEY, val);
|
||||
status.textContent = '保存しました';
|
||||
status.style.color = 'var(--accent)';
|
||||
});
|
||||
})();
|
||||
|
||||
// ── コミット読み込み ──────────────────
|
||||
document.getElementById('loadCommitsBtn').addEventListener('click', async () => {
|
||||
const token = getToken();
|
||||
if (!token) { showToast('ログインが必要です'); return; }
|
||||
const ghPat = getGhPat();
|
||||
if (!ghPat) {
|
||||
showToast('設定パネルで GitHub PAT を設定してください');
|
||||
document.getElementById('settingsBtn').click();
|
||||
return;
|
||||
}
|
||||
|
||||
const btn = document.getElementById('loadCommitsBtn');
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span class="spinner" style="border-color:rgba(0,0,0,.15);border-top-color:var(--text2)"></span> 読み込み中';
|
||||
|
||||
const since = new Date(Date.now() - activeDays * 86400000).toISOString();
|
||||
|
||||
try {
|
||||
const resp = await fetch(`${API}/chronicle/activity?days=${activeDays}`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const resp = await fetch(
|
||||
'https://api.github.com/orgs/posimai/events?per_page=100',
|
||||
{ headers: { 'Authorization': `Bearer ${ghPat}`, 'Accept': 'application/vnd.github+json' } }
|
||||
);
|
||||
if (resp.status === 401) throw new Error('PAT が無効です。設定を確認してください');
|
||||
if (!resp.ok) throw new Error(`GitHub API ${resp.status}`);
|
||||
|
||||
if (resp.status === 503) {
|
||||
showToast('VPS に CHRONICLE_GITHUB_TOKEN が未設定です');
|
||||
return;
|
||||
const events = await resp.json();
|
||||
const commits = [];
|
||||
const byRepo = {};
|
||||
|
||||
for (const ev of events) {
|
||||
if (ev.type !== 'PushEvent') continue;
|
||||
if (ev.created_at < since) continue;
|
||||
const repo = ev.repo.name.replace('posimai/', '');
|
||||
if (!byRepo[repo]) byRepo[repo] = [];
|
||||
for (const c of ev.payload?.commits || []) {
|
||||
const msg = c.message.split('\n')[0];
|
||||
if (/^Merge\b/i.test(msg)) continue;
|
||||
byRepo[repo].push(msg);
|
||||
commits.push(msg);
|
||||
}
|
||||
}
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
||||
|
||||
const data = await resp.json();
|
||||
if (!data.commits?.length) {
|
||||
if (!commits.length) {
|
||||
showToast('この期間にコミットが見つかりませんでした');
|
||||
return;
|
||||
}
|
||||
|
||||
const byRepo = {};
|
||||
for (const c of data.commits) {
|
||||
if (!byRepo[c.repo]) byRepo[c.repo] = [];
|
||||
byRepo[c.repo].push(c.message);
|
||||
}
|
||||
|
||||
const lines = [];
|
||||
for (const [repo, messages] of Object.entries(byRepo)) {
|
||||
lines.push(`【${repo}】`);
|
||||
for (const m of messages) lines.push(`- ${m}`);
|
||||
}
|
||||
|
||||
const area = document.getElementById('activities');
|
||||
area.value = lines.join('\n');
|
||||
showToast(`${data.commits.length} 件のコミットを読み込みました`);
|
||||
document.getElementById('activities').value = lines.join('\n');
|
||||
showToast(`${commits.length} 件のコミットを読み込みました`);
|
||||
} catch (e) {
|
||||
showToast(`読み込み失敗: ${e.message}`);
|
||||
} finally {
|
||||
|
|
|
|||
Loading…
Reference in New Issue