Files
devdesk/web/src/repo.js
T
jaredandClaude Opus 5.5 be9b026a01
build-deb / Lint, test, package (push) Successful in 2m12s
build-deb / Deploy to CT 126 (push) Successful in 3s
build-deb / Notify on failure (push) Skipped
feat: v0.5.0 header, switcher, phone key bar, shared polling, Matrix "needs you"
- Header: no SSO chip ("Sign in again" only on expiry), state dot on the
  session chip, LIVE as a dot, ⋯ menu for text size/notifications/fullscreen,
  Panels badge for waiting sessions and alerts.
- Session switcher on the chip; bare URL reattaches the last session; + New
  opens the panel form with project folders.
- Notifications when other sessions start waiting; alerts polled with the
  panels closed; one tab polls for all tabs over BroadcastChannel.
- Sidebar: context bar per session instead of the Context panel; compact
  Repo/CI with "Ask Claude to fix CI"; legible labels.
- Phone: key bar, drawer with backdrop, visualViewport-aware layout, DOM
  renderer on touch, compact connection dot.
- devdesk-notify-matrix: one Matrix message per wait that lasts
  DEVDESK_MATRIX_DELAY seconds with nobody attached.

Closes #8
Closes #13
Closes #14
Closes #15
Closes #16
Closes #17
Closes #28

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 23:34:59 -04:00

62 lines
2.4 KiB
JavaScript

// Repo / CI panel: git state of the current session's folder plus the Gitea CI
// status of its HEAD commit (`devdesk attach --repo <session>`).
const CI = {
success: ['passing', 'lt-status-completed'],
failure: ['failed', 'lt-status-failed'],
error: ['error', 'lt-status-failed'],
pending: ['running', 'lt-status-running'],
warning: ['warning', 'lt-status-pending'],
};
function link(href, text) {
const a = document.createElement('a');
a.href = href;
a.target = '_blank';
a.rel = 'noopener';
a.textContent = text;
return a;
}
export function renderRepo(root, repo) {
const field = (name) => root.querySelector(`[data-field="${name}"]`);
const set = (name, value) => field(name).replaceChildren(value);
const grid = root.querySelector('.dd-repo-grid');
const note = root.querySelector('.dd-repo-note');
const fix = root.querySelector('.dd-fix-ci');
fix.hidden = true;
// No repository: one line instead of a grid of dashes (devdesk#17).
if (!repo || !repo.git) {
root.dataset.state = 'empty';
grid.hidden = true;
note.textContent = repo ? `Not a git repository: ${repo.dir}` : 'Open a session to see its repository.';
return;
}
root.dataset.state = 'live';
grid.hidden = false;
set('repo', repo.url ? link(repo.url, repo.repo) : (repo.remote || 'no remote'));
const sync = repo.upstream
? [repo.ahead ? `↑${repo.ahead}` : '', repo.behind ? `↓${repo.behind}` : ''].filter(Boolean).join(' ') || 'in sync'
: 'no upstream';
set('branch', `${repo.branch} @ ${repo.sha || '—'} · ${sync}`);
set('dirty', repo.dirty ? `${repo.dirty} changed` : 'clean');
const ci = field('ci');
const [label, cls] = repo.ci?.total ? (CI[repo.ci.state] || [repo.ci.state, 'lt-status-pending'])
: [repo.ahead ? 'not pushed' : 'no CI', ''];
ci.className = `lt-status ${cls}`;
ci.replaceChildren(repo.ci?.url ? link(repo.ci.url, label) : label);
set('prs', repo.url && repo.prs != null ? link(`${repo.url}/pulls`, `${repo.prs} open`) : '—');
note.textContent = repo.repo ? '' : 'Not a Gitea repository; CI status unavailable.';
if (repo.ci?.total && ['failure', 'error'].includes(repo.ci.state)) {
fix.hidden = false;
fix.dataset.askClaude = `CI is failing for ${repo.repo} on ${repo.branch} at ${repo.sha}`
+ ` (${repo.ci.url || 'see Gitea Actions'}). Use the gitea MCP server to read the failed job's log,`
+ ' find the cause, and fix it. Tell me the plan before pushing anything.';
}
}