Add git widget to session cards in dashboard
This commit is contained in:
parent
599f911964
commit
ae0251b6d3
1 changed files with 151 additions and 0 deletions
|
|
@ -500,6 +500,69 @@
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.git-line {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-additions {
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-deletions {
|
||||||
|
color: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-file {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-file-modified {
|
||||||
|
color: #ff9800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-file-added {
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-file-deleted {
|
||||||
|
color: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-file-untracked {
|
||||||
|
color: #9e9e9e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-files {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-files summary {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-files summary:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-file-list {
|
||||||
|
margin-top: 4px;
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.git-file-more {
|
||||||
|
color: #666;
|
||||||
|
font-style: italic;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
padding: 32px 16px;
|
padding: 32px 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -696,6 +759,8 @@
|
||||||
mode: 'normal',
|
mode: 'normal',
|
||||||
model: null,
|
model: null,
|
||||||
idle_since: null,
|
idle_since: null,
|
||||||
|
git_branch: null,
|
||||||
|
git_files_json: null,
|
||||||
});
|
});
|
||||||
renderSessions();
|
renderSessions();
|
||||||
});
|
});
|
||||||
|
|
@ -758,6 +823,16 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
es.addEventListener('git', (e) => {
|
||||||
|
const data = JSON.parse(e.data);
|
||||||
|
const session = state.sessions.get(data.session_id);
|
||||||
|
if (session) {
|
||||||
|
session.git_branch = data.branch;
|
||||||
|
session.git_files_json = data.files_json;
|
||||||
|
updateStatsWidget(data.session_id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
state.eventSource = es;
|
state.eventSource = es;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -790,6 +865,14 @@
|
||||||
return `${Math.floor(seconds / 3600)}h`;
|
return `${Math.floor(seconds / 3600)}h`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFileClass(status) {
|
||||||
|
if (status === 'M') return 'git-file-modified';
|
||||||
|
if (status === 'A') return 'git-file-added';
|
||||||
|
if (status === 'D') return 'git-file-deleted';
|
||||||
|
if (status === '??') return 'git-file-untracked';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
function renderStatsWidget(session) {
|
function renderStatsWidget(session) {
|
||||||
const lines = [];
|
const lines = [];
|
||||||
|
|
||||||
|
|
@ -831,6 +914,74 @@
|
||||||
lines.push(`<div class="stats-line">${badges.join(' ')}</div>`);
|
lines.push(`<div class="stats-line">${badges.join(' ')}</div>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Git info
|
||||||
|
if (session.git_branch || session.git_files_json) {
|
||||||
|
const gitParts = [];
|
||||||
|
let files = [];
|
||||||
|
let totalAdditions = 0;
|
||||||
|
let totalDeletions = 0;
|
||||||
|
|
||||||
|
// Parse files if available
|
||||||
|
if (session.git_files_json) {
|
||||||
|
try {
|
||||||
|
files = JSON.parse(session.git_files_json);
|
||||||
|
files.forEach(f => {
|
||||||
|
totalAdditions += f.additions || 0;
|
||||||
|
totalDeletions += f.deletions || 0;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse git files JSON:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build git summary line
|
||||||
|
if (session.git_branch) {
|
||||||
|
gitParts.push(`<span class="git-icon">⎇</span>`);
|
||||||
|
gitParts.push(`<span class="stats-value">${escapeHtml(session.git_branch)}</span>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files.length > 0) {
|
||||||
|
gitParts.push(`| <span class="stats-value">${files.length}</span> file${files.length === 1 ? '' : 's'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalAdditions > 0) {
|
||||||
|
gitParts.push(`| <span class="git-additions">+${totalAdditions}</span>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalDeletions > 0) {
|
||||||
|
gitParts.push(`| <span class="git-deletions">-${totalDeletions}</span>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gitParts.length > 0) {
|
||||||
|
let gitLine = `<div class="stats-line git-line">${gitParts.join(' ')}</div>`;
|
||||||
|
|
||||||
|
// Add collapsible file list if there are files
|
||||||
|
if (files.length > 0) {
|
||||||
|
const fileListItems = files.slice(0, 10).map(f => {
|
||||||
|
const filePath = escapeHtml(f.path);
|
||||||
|
const fileClass = getFileClass(f.status);
|
||||||
|
const additions = f.additions ? `<span class="git-additions">+${f.additions}</span>` : '';
|
||||||
|
const deletions = f.deletions ? `<span class="git-deletions">-${f.deletions}</span>` : '';
|
||||||
|
return `<div class="git-file ${fileClass}">${escapeHtml(f.status)} ${filePath} ${additions} ${deletions}</div>`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
const moreText = files.length > 10 ? `<div class="git-file-more">and ${files.length - 10} more...</div>` : '';
|
||||||
|
|
||||||
|
gitLine += `
|
||||||
|
<details class="git-files">
|
||||||
|
<summary>${files.length} changed file${files.length === 1 ? '' : 's'}</summary>
|
||||||
|
<div class="git-file-list">
|
||||||
|
${fileListItems}
|
||||||
|
${moreText}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push(gitLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (lines.length === 0) {
|
if (lines.length === 0) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue