refactor(dashboard): SSoT GitHub links in deploy routes#6389
Conversation
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — a behavior-preserving refactor that consolidates ad-hoc https://github.com/... string construction across deploy-route components into a single source-of-truth module.
- New
github-urls.tsmodule — five builders (githubRepoUrl,githubCommitUrl,githubBranchUrl,githubPullUrl,githubDeploymentUrl) that each returnundefinedwhen a required part is missing, so callers fall back to plain text instead of rendering broken links. - Fork-aware routing in
githubDeploymentUrl— prefers the PR link (always anchored to the base repo) and falls back to the commit onforkRepoFullName || repoFullName, with theprNumber != nullgate correctly treating0as present. - Consumers rewired —
sentinel-log-details,deployment-approval,project-details-content,create-deployment-button,active-deployment-card, and both list views now thread URLs through the builders; all use truthiness checks, so the priornullsentinel becomingundefinedis behaviorally inert. - tRPC list endpoints —
deploy/app/list.tsanddeploy/project/list.tsnow selectgitCommitSha,prNumber, andforkRepositoryFullNamefromdeploymentsand flatten them into list payloads; collection schemas (apps.ts,projects.ts) and optimistic-insert sites gain the matching nullable fields. - Thorough vitest coverage —
github-urls.test.tsexercises every builder, the missing-part fallbacks, theprNumber === 0edge case, and fork-vs-base PR routing.
The only real behavior change is in resource-card.tsx: the commit title in project/app lists was previously a dead <Link href="#"> and now renders a real external <a> (or a plain <span> for image-based deployments). That is an intended improvement. Schema additions match the existing deployments.ts types, and all link consumers preserve their fallback semantics. Clean and mergeable.
Claude Opus | 𝕏
There was a problem hiding this comment.
ℹ️ No critical issues — one minor scope observation inline.
Reviewed changes — the delta since the prior pullfrog review (c1beac0) reworks the github-link layer from standalone functions into a namespaced object backed by a new generic url-assembly module.
- Renamed
github-urls.ts→github-url.ts— the five standalone builders (githubRepoUrl,githubCommitUrl, etc.) become methods on a singlegithubUrlobject (.repo,.commit,.branch,.pull,.deployment); all consumers and the test suite are rewired accordingly. Output is identical, so this is behavior-preserving. - New
lib/navigation/url.tsmodule — low-level verbatim url assembly (buildUrl,withQuery,toQueryString); thegithubUrlbuilders now delegate tobuildUrlinstead of inlining template literals. - Test coverage —
lib/navigation/url.test.tsexercisesbuildUrl/withQuery/toQueryString(including thenull/undefined-drop and0/false-keep semantics, and unencoded:in values);github-url.test.tsupdated to the new namespace.
The refactor is sound and the new module is well-tested. The verbatim no-encoding contract is consistent with the dashboard's existing ?<field>=<operator>:<value> logs-filter convention.
ℹ️ navigation/url ships query-string machinery with no production caller
The new module exports withQuery and toQueryString, and buildUrl accepts a query part — but every production caller is github-url.ts, which only ever passes base + segments and never query. The query path is currently exercised solely by its own tests.
This isn't a bug, and the dashboard's logs-filter URLs are an obvious future consumer, so it's reasonable to keep. Flagging only because AGENTS.md calls out "no speculative features" — worth a one-line confirmation that the query helpers are intended to land a follow-up that wires them into the logs-nav builders, rather than sitting dead.
Claude Opus | 𝕏
dave-hawkins
left a comment
There was a problem hiding this comment.
LGTM. Would be good to get others opinions too tho, but i don't have any strong opinions on this!
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — the delta since the prior pullfrog review (a4cca98) is one substantive correctness fix to the project-list payload; the rest is a Merge branch 'main' pulling base-branch progress.
- Fixed repo/commit mismatch in
deploy/project/list.ts— the repo lookup was keyed byproject.id, so a multi-app project could pair its primary app's commit/PR with whichever repo connection won for the project. The query now selectsapps.id(stored asappIdonprimaryAppByProject) andgithubRepoConnections.appId, andrepoByAppis keyed byappIdso the repo matches the app that supplied the commit. This alignsproject/list.tswithapp/list.ts, which already keyed byappId.
The fix is sound: github_repo_connections.app_id is notNull().unique() in the schema, so the appId key is a safe unique identity and the repoByApp.has(row.appId) dedup is harmless/defensive. The repo query also gains an inArray(githubRepoConnections.projectId, projectIds) scope, narrowing it from all workspace connections — behavior-preserving given the keyed lookup. The inline comment explaining the multi-app rationale is accurate. Prior informational thread (review 4459458696) is resolved — author confirmed PR #6393 will consume the query helpers.
Claude Opus | 𝕏

TLDR; we were creating Github URLs all over the /projects routes, but now we call them from the single place.
Problem
We are constructing Github URLs all over the place, because we need to tell people what caused that deployment or which branch/repo leads to where in Github.
Fix
Instead of constructing them manually in every component we need, we'll thread them through functions like these. This will give us ability to control those in a single place and allow us to add prefixes, suffixes if need to URLs.
Test
mise exec -- pnpm --dir=web/apps/dashboard vitest run lib/navigation/url.test.ts lib/github-url.test.tsThose should pass.
Setup
GitHub links (each resolves to the right page)
create-deployment-button.tsx) → branch.resource-card.tsx) in app list + project list → correct PR number, else commit.active-deployment-card) marked items → correct commit/branch.deployment-approval.tsx) generates correct URLs. Fork case: open a PR from a fork — commit/branch links point at the fork repo, the PR link at the base repo.