Mark which patch on a ticket is the latest, PR or attachment - #140
Merged
juanmaguitar merged 2 commits intoAug 7, 2026
Merged
Conversation
juanmaguitar
force-pushed
the
juanmaguitar/latest-patch
branch
from
August 7, 2026 05:19
932f767 to
69bdc99
Compare
juanmaguitar
force-pushed
the
juanmaguitar/latest-patch
branch
from
August 7, 2026 06:28
69bdc99 to
6d35bbc
Compare
juanmaguitar
force-pushed
the
juanmaguitar/latest-patch
branch
from
August 7, 2026 06:47
6d35bbc to
8df2335
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Marks the latest loaded patch across linked PRs and Trac attachments.
Changes:
- Adds UTC-based patch-date comparison logic.
- Displays “Latest” pills and an attachment notice.
- Adds unit coverage for source and date edge cases.
Review: 2 [fix here] findings: long titles or filenames can clip the “Latest” pill.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/latest-patch.cjs |
Selects the latest applicable patch. |
src/renderer/index.jsx |
Renders latest-patch indicators. |
test/latest-patch.test.cjs |
Tests selection and timestamp parsing. |
Suppressed comments (1)
src/renderer/index.jsx:2431
- [UI · 🔵 low · fix here] The filename and pill share the same nowrap, overflow-hidden container, so a sufficiently long attachment filename hides the “Latest” pill. Keep the pill as a non-shrinking sibling and apply ellipsis only to the filename portion so the marker remains visible.
{latestPill(latestPatch?.kind === 'attachment' && latestPatch.key === att.url)}
| <div style={{ fontSize: 13, color: '#1d2327', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}> | ||
| <Button variant="link" onClick={() => window.api.openExternal(pr.url)} style={{ fontSize: 13 }}>#{pr.number}</Button> | ||
| {' '}{pr.title} | ||
| {latestPill(latestPatch?.kind === 'pr' && latestPatch.key === pr.number)} |
Collaborator
Author
There was a problem hiding this comment.
Fixed in b39037e. Each heading is now a flex row: an inner span ellipsizes the title (or filename) alone, and the pill sits beside it as a non-shrinking sibling, so it survives any title length. Same change applied to the attachment row at line 2431.
juanmaguitar
force-pushed
the
juanmaguitar/latest-patch
branch
from
August 7, 2026 07:58
8df2335 to
ce7f921
Compare
juanmaguitar
force-pushed
the
juanmaguitar/latest-patch
branch
from
August 7, 2026 09:15
ce7f921 to
65ec966
Compare
A contributor arriving at a ticket wants to try the latest fix. The panel
listed PRs and Trac attachments as two separate sections, but nothing said
which one — across both — was the most recent. Usually it is a PR, and the PR
list is there immediately; but sometimes the newest fix is a .diff uploaded to
Trac, and that was buried under the attachments button with no signal.
Now the newest known patch carries a "Latest" pill, whether it is a PR row or
an attachment row, and when the newest is an attachment a note says so
explicitly — "the most recent patch on this ticket is a file attachment, not a
pull request". Because attachments load on demand, "latest" is judged across
what is loaded: PRs alone until the contributor opens attachments (the normal
case), then both. Opening the attachments cannot be forced on every ticket, so
the verdict simply completes once they are looked at.
The comparison lives in a pure module (src/latest-patch.cjs), unit tested. A PR
is dated by updatedAt, an attachment by its scraped upload time; a .txt never
competes, and a relative-only date ("15 months ago") cannot win. The attachment
timestamp is anchored to UTC by hand rather than parsed in the machine's local
zone, so two contributors in different timezones see the same patch marked
latest — the point of the feature is a consistent answer.
Refs #109, #11, part of #110.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
juanmaguitar
force-pushed
the
juanmaguitar/latest-patch
branch
from
August 7, 2026 09:41
65ec966 to
b035ff0
Compare
The pill shared one nowrap/overflow-hidden box with the PR title and the attachment filename, so a long enough title ellipsized straight past it — hiding the only per-row signal exactly on the rows most likely to have it. Each heading is now a flex row: an inner span ellipsizes the title alone, and the pill sits beside it as a non-shrinking sibling. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
juanmaguitar
added a commit
that referenced
this pull request
Aug 7, 2026
Part of #110. Refs #109, #11. **Stacked on #140** (base is that branch), atop #139 → #136 → #135 → #123. From hands-on testing of the stack. ## Three fixes reported from testing 1. **The apply error persisted after Cancel.** Applying a PR that no longer fits ("…has moved on since the patch was written") showed an error; clicking Cancel dismissed the preview but left the error on screen. Cancel now clears it too. 2. **The "Try someone else's patch" sub-copy contradicted itself during a PR preview** — it said "Apply a `.diff`/`.patch` file…" while showing "PR #4496 changes 1 file". The sub-copy is now hidden whenever a preview or the apply chain is showing (the preview card speaks for itself), and the idle copy names pull requests as well as files. 3. **The failure message ran two sentences together** ("…no longer applies The checkout was not changed."). A period is inserted when the reason doesn't already end in punctuation. ## One requested addition **Apply a PR straight from a pasted URL or number**, without it having to be linked to the ticket. A "Paste a pull request URL or number" input + "Apply PR" button in the panel's idle state. `parsePrRef` (pure, `src/patch-sources.cjs`) accepts a wordpress-develop PR URL or a bare number and rejects other repos, other hosts, issue URLs and junk — including crafted `..` paths (URL normalisation collapses them, then the repo/anchor check rejects). The number rides the **existing** `previewPr → fetchPrDiff → preview → apply` flow, so a pasted PR shares the same trust boundary as the linked-PR list: `fetchPrDiff` hardcodes the repo and strips the number to digits, and the diff flows through the apply engine's path-traversal defence. ## Testing - `test/patch-sources.test.cjs` — `parsePrRef`: bare/`#`number, URL with trailing `/files` and `#…`, scheme-less, wrong-repo rejection, and issue/foreign-host/junk rejects. - `npm test` / `npm run test:electron`: **242/242** both runtimes. `npm run lint`: clean. ## Self-review (per AGENTS.md) Judgement pass on fresh context: **0 findings** across the five dimensions. It independently confirmed the `..`-traversal and foreign-repo/host rejections, that the pasted-number path introduces no new trust boundary (same `fetchPrDiff` + apply engine), that the punctuation ternary can't throw (error is truthy-guarded), and that hiding the sub-copy never strips the idle call-to-action. Pending your visual confirm in the running app for the three UI fixes and the paste-a-PR flow — these are your reported issues, verified here by tests + review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #110. Refs #109, #11. Stacked on #139 (base is that branch), which stacks on #136 → #135 → #123. Review order: #123 → #135 → #136 → #139 → this.
Why
A contributor arriving at a ticket wants to try the latest fix. The panel listed PRs and Trac attachments as two separate sections, but nothing said which one — across both — was the most recent. Usually it's a PR (visible immediately); but sometimes the newest fix is a
.diffuploaded to Trac, and that was buried under the attachments button with no signal.What this does
How
The comparison is a pure module (
src/latest-patch.cjs), unit tested. A PR is dated byupdatedAt, an attachment by its scraped upload time. A.txtnever competes; a relative-only date ("15 months ago") can't win. The attachment timestamp is anchored to UTC by hand rather than parsed in the machine's local zone, so two contributors in different timezones see the same patch marked latest — a consistent answer is the whole point.Testing
test/latest-patch.test.cjs— PR-wins (normal), attachment-wins-once-loaded (the case the feature exists for),.txtexcluded, relative-date can't win, attachments-only, empty→null, and the UTC-determinism of the date parse (PM/AM and the 12-o'clock edge).npm test/npm run test:electron: 238/238 both runtimes.npm run lint: clean.Self-review (per AGENTS.md)
Ran the review with the judgement pass on fresh context. It returned 0
[fix here]· 1[follow-up]— the follow-up was the timezone skew (PR date is UTC ISO, attachment date was parsed in local time), which two contributors could see differently. Fixed before this PR by anchoring the attachment parse to UTC, with a determinism test. The reviewer verified the key/equality logic (exactly one row marked, right row), NaN/.txtexclusion, null-safety, and stale-state reset on ticket switch.🤖 Generated with Claude Code