Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/811-repo-header.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The repository header now separates the title and target branch, a compact status strip (automatic work, discovery interval, next run, schedule console, FlyBot and GitHub credential) and a facts line, instead of one long paragraph carrying every fact.
10 changes: 7 additions & 3 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,13 @@ recorded". `scripts/restore-drill.mjs --status-file` is the writer.
opens the section that holds it — so a reader without the script still gets
the whole page. The bar sticks at `var(--header-h)` and scrolls horizontally
in the phone band; the tab is a 44px `--touch` target and the current tab
paints with `--accent-strong`, the one interactive accent. The Danger section
also carries the recent-auth preflight: a stale `recent_auth_at` renders a
**Confirm with GitHub** link whose return target is `/repos/:id#danger`; the
paints with `--accent-strong`, the one interactive accent. Above the tabs, the
header separates the title and target branch, a status strip (automatic work,
discovery interval, next run, schedule console, FlyBot, GitHub credential) and
a facts line (upstream/fork, permission, role, reviewer); the run/plan/review
actions stay in the header and every existing anchor is unchanged. The Danger
section also carries the recent-auth preflight: a stale `recent_auth_at` renders
a **Confirm with GitHub** link whose return target is `/repos/:id#danger`; the
stale POST refusal uses the same anchor, so the form is on screen after
re-authentication instead of the page top.
- **Dashboard job filters** (`src/lib/jobFilters.ts`): `/dashboard` accepts
Expand Down
11 changes: 11 additions & 0 deletions public/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,17 @@ p { margin: 0 0 12px; }
.work-actions summary { cursor: pointer; color: var(--accent); font-size: var(--text-sm); font-weight: 650; }
.work-actions .row { margin-top: 8px; }
@media (max-width: 680px) { .work-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.repo-head { align-items: flex-start; }
.repo-head-main { display: grid; gap: 8px; min-width: 0; }
.repo-status-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; min-width: 0; }
.repo-status { display: inline-flex; align-items: baseline; gap: 6px; min-width: 0; padding: 4px 8px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--field); color: var(--text); font-size: var(--text-sm); text-decoration: none; }
.repo-status .fine { color: var(--muted); }
.repo-status b { font-weight: 650; }
a.repo-status:hover { border-color: var(--accent); }
@media (max-width: 680px) {
.repo-status-strip { gap: 6px; }
.repo-status { flex: 1 1 calc(50% - 6px); }
}
.repo-subnav {
position: sticky; top: var(--header-h); z-index: 15;
display: flex; gap: var(--space-2); margin: 0 0 var(--space-4); min-height: var(--subnav-h);
Expand Down
15 changes: 12 additions & 3 deletions src/views/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1495,11 +1495,20 @@ export function repoPage(input: { config: Config; locale: Locale; viewer: Viewer
const teamGrid = teamRoles.length === 0 ? '' : `<div class="team-grid">${teamRoles.map((role) => `<div class="team-role"><b>${escapeHtml(role.label)}</b><span>${escapeHtml(role.note)}</span></div>`).join('')}</div>
<details class="fine session-details"><summary>${escapeHtml(t('查看 session ID', 'View session IDs'))}</summary><div class="session-list">${teamRoles.map((role) => `<code>${escapeHtml(role.label)}: ${escapeHtml(role.id)}</code>`).join('')}</div></details>`
const repoHeader = `<section class="card">
<div class="row between">
<div>
<div class="row between repo-head">
<div class="repo-head-main">
<div class="eyebrow">${escapeHtml(t('仓库', 'REPOSITORY'))}</div>
<h1>${escapeHtml(upstreamOwner)}/${escapeHtml(upstreamName)}</h1>
<p class="muted">${escapeHtml(t('目标分支', 'Target branch'))} <code>${escapeHtml(targetBranch)}</code>${targetBranch === defaultBranch ? '' : ` · ${escapeHtml(t('默认分支', 'Default branch'))} <code>${escapeHtml(defaultBranch)}</code>`} · ${escapeHtml(repo.auto_iterate === 1 ? t('自动迭代已开启', 'Auto-iteration on') : t('仅手动运行', 'Manual runs only'))} · ${escapeHtml(t('自动间隔', 'Auto every'))} <b>${escapeHtml(intervalLabel(repo.interval_minutes, t))}</b> · ${escapeHtml(t('下次约', 'Next'))} <span data-next-run data-next-source="${escapeHtml(scheduledNext === undefined ? 'interval' : 'schedule')}">${escapeHtml(nextRunText)}</span> · <a href="/repos/${escapeHtml(repo.id)}/schedule">${escapeHtml(t('排期控制台', 'Schedule console'))}</a> · ${badge(t, repo.last_status ?? 'idle')}</p>
<p class="fine">${escapeHtml(t('目标分支', 'Target branch'))} <code>${escapeHtml(targetBranch)}</code>${targetBranch === defaultBranch ? '' : ` · ${escapeHtml(t('默认分支', 'Default branch'))} <code>${escapeHtml(defaultBranch)}</code>`}</p>
<div class="repo-status-strip">
<span class="repo-status"><span class="fine">${escapeHtml(t('自动迭代', 'Automatic work'))}</span><b>${escapeHtml(repo.auto_iterate === 1 ? t('自动迭代已开启', 'Auto-iteration on') : t('仅手动运行', 'Manual runs only'))}</b></span>
<span class="repo-status"><span class="fine">${escapeHtml(t('自动间隔', 'Auto every'))}</span><b>${escapeHtml(intervalLabel(repo.interval_minutes, t))}</b></span>
<span class="repo-status"><span class="fine">${escapeHtml(t('下次约', 'Next'))}</span><span data-next-run data-next-source="${escapeHtml(scheduledNext === undefined ? 'interval' : 'schedule')}">${escapeHtml(nextRunText)}</span></span>
<a class="repo-status" href="/repos/${escapeHtml(repo.id)}/schedule">${escapeHtml(t('排期控制台', 'Schedule console'))}</a>
<span class="repo-status"><span class="fine">FlyBot</span>${flybotAvailable ? (instance === undefined ? escapeHtml(t('未创建', 'not created')) : badge(t, instance.status)) : escapeHtml(t('未启用', 'not enabled'))}</span>
<span class="repo-status"><span class="fine">${escapeHtml(t('GitHub 凭据', 'GitHub credential'))}</span><span class="badge ${credentialOk ? 'good' : 'bad'}">${escapeHtml(credentialOk ? t('正常', 'ok') : t('失效', 'invalid'))}</span></span>
${badge(t, repo.last_status ?? 'idle')}
</div>
<p class="fine">${escapeHtml(t('上游', 'Upstream'))} <a href="${escapeHtml(upstreamUrl)}" target="_blank" rel="noreferrer">${escapeHtml(upstreamOwner)}/${escapeHtml(upstreamName)}</a> · ${repo.is_fork === 1 ? `${escapeHtml(t('Fork', 'Fork'))} <a href="${escapeHtml(forkUrl)}" target="_blank" rel="noreferrer">${escapeHtml(forkOwner)}/${escapeHtml(forkName)}</a>` : escapeHtml(t('自有仓库,无需 fork', 'Own repository, no fork'))} · ${escapeHtml(t('GitHub 权限', 'GitHub permission'))} <code>${escapeHtml(permission)}</code> · ${escapeHtml(t('你的角色', 'Your role'))} <code>${escapeHtml(repoRoleLabel(t, repoRole))}</code> · ${escapeHtml(reviewerLabel)}</p>
</div>
<div class="row">
Expand Down
Loading