feat(github-actions-grafana-jump)!: page-based jump links - every entry is just a name and a URL - #45
Merged
Merged
Conversation
Userscript Version PreviewPreview only — versions and CHANGELOGs are bumped automatically on merge to
|
Replaces the old `targets:` list (each entry a `type: dashboard` or
`type: trace` with a `baseUrl` and a set of var-name mappings) with a
`pages:` list, one entry per kind of GitHub page, each holding plain
name + URL links.
The header now documents every supported page kind, which GitHub page
each name means, and exactly which `{{field}}` placeholders that page
provides. That field list is generated by pageFieldsReference() in the
userscript source and asserted against this file by a test, so it can't
drift from the code.
Co-Authored-By: Claude <noreply@anthropic.com>
…k, organized by page
Every config entry is now just a name and a URL you write yourself. The
`type: dashboard` / `type: trace` distinction, the top-level `baseUrl`,
and the Grafana/Tempo URL builders they fed are all gone - a Grafana
dashboard or a Tempo trace link is now simply a full URL with
`{{field}}` placeholders in it, same as any other link.
The config is also reorganized around pages instead of inferring where a
link belongs from which fields its URL happens to use. The top level is a
list of pages, each with its own links, and a link only ever shows up on
the page kind it's declared under.
Alongside that:
- Adds six page kinds that had no representation before: the repo home
page, a file view, the pull request list, the branch list, the Actions
tab itself, and a single job within a run (previously folded into the
run page, which made `jobId` an optional field on it).
- Replaces the hardcoded pull-request-only inline placement, and the
"float unless this is a PR" rule around it, with a per-page-kind
toolbar selector table. Each page's buttons go in that page's own
GitHub toolbar, styled as Primer buttons; the floating button remains
the fallback for a page with no toolbar entry or whose toolbar isn't
found. The old `[class^="gh-header-actions"]` PR selector was dead -
that header is now `[class^="prc-PageHeader-Actions-"]`.
- The two list pages instead get a small link per row, revealed on hover
or keyboard focus, scoped to that row's own PR number or branch name -
the same mechanism Primer uses for its own trailing row actions.
- Keeps the injected container in place across GitHub's own React
re-renders, which discard it without the URL changing (seen on a
workflow run page). Placement is re-checked on every DOM mutation, and
the container's contents carry a signature so re-rendering identical
content is a no-op rather than a mutation that triggers another pass.
- Bumps the stored-config key to `jumpLinksConfig.v2`; nothing reads the
v1 value, so an existing personal config is left alone rather than
half-migrated into a shape it can't express.
The package name and its "Grafana" branding are deliberately untouched
here; renaming it is its own change.
BREAKING CHANGE: personal and repo configs in the old `targets:` format
are no longer read. Repo configs need rewriting in the new `pages:`
format, and personal configs need re-entering through the config panel.
Co-Authored-By: Claude <noreply@anthropic.com>
…hema Replaces the dashboard/trace URL-builder tests with tests for what the script actually does now: the new config parse/normalize/serialize path, the six new page-kind URL parsers, per-page field availability, and the placeholder gate that hides a link whose URL wants a field its page doesn't provide. Three of these exist to catch drift rather than to test logic: - every page kind declared in JUMP_PAGE_KINDS is reachable from resolveJumpContext(), so adding a kind without a parser fails - the generated field reference matches each page's actual fields - this repo's own checked-in .github/jump-links.config.yaml still parses, and each page's links all survive the placeholder gate Co-Authored-By: Claude <noreply@anthropic.com>
nsheaps
force-pushed
the
n8bot/page-based-jump-links
branch
from
August 8, 2026 02:51
a6b972f to
afeb7b7
Compare
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.
What this changes
Two things, together, because they only make sense together.
1. Every config entry is now just a link. A name you word however you like, and a URL you write yourself with
{{field}}placeholders in it. Thetype: dashboard/type: tracesplit is gone, along with the top-levelbaseUrland the two URL builders those types fed. A Grafana dashboard link and a Tempo trace link are now both plain URLs — you paste the URL you already have and swap the parts that vary for placeholders.2. The config is organized by page instead of by guesswork. It used to infer where a link belonged from which fields its URL happened to use. Now the top level is a list of pages, each with its own links, and a link only shows up on the page kind it's listed under.
Where the links actually show up
flowchart TD A[Page loads or DOM mutates] --> B{Which kind of page?} B -->|PR list, branch list| C[One small link per row,<br/>revealed on hover or focus,<br/>scoped to that row] B -->|Has a known toolbar| D{Toolbar found?} B -->|No toolbar entry| F[Floating button,<br/>bottom right] D -->|yes| E[Primer-styled buttons<br/>in GitHub's own toolbar] D -->|no| FPreviously this was a single hardcoded special case: pull request pages got an inline button, and everything else floated. Now each page kind has its own toolbar selector, and the floating button is the fallback rather than the norm. The old PR selector
[class^="gh-header-actions"]was dead — that header is[class^="prc-PageHeader-Actions-"]now.New page kinds
Six pages had no representation at all before: the repo home page, a file view, the pull request list, the branch list, the Actions tab itself, and a single job within a run. That last one used to be folded into the run page, which is why
jobIdwas an optional field on it; they're separate kinds now.The two list pages work differently from the rest — instead of one button for the page, each row gets its own link pointing at that row's own PR or branch, revealed on hover or keyboard focus. That's the same mechanism Primer uses for its own trailing row actions (
:hover, :focus-withinon the row), and it fades rather than hides so the links stay in the tab order.Also in here
CONTAINER_IDstill describing the old "PR gets inline, everything else floats" rule..github/jump-links.config.yamlis generated from the code, and a test asserts the file matches. Two more drift tests: every declared page kind has to be reachable fromresolveJumpContext(), and this repo's own checked-in config has to still parse with all its links surviving the placeholder gate.jumpLinksConfig.v2. Nothing reads v1, so an existing personal config is left alone rather than half-migrated into a shape it can't express.Breaking
Configs in the old
targets:format aren't read any more. Repo configs need rewriting in thepages:format; personal configs need re-entering through the config panel. Renaming the package away from its "Grafana" branding is deliberately not in here — that's its own change.How this was verified
Code-correct: typecheck clean, 58 unit tests passing, build script runs,
oxlintclean for this package (the warnings it prints are pre-existing, in other packages).Live on real github.com pages, with the compiled build injected into the page and a fake config — repo home, file view, PR list, branch list, one workflow's runs, and a run. Buttons landed in the right toolbar with the right text and the right filled-in URLs; per-row hover links appeared on only the hovered row with that row's own PR number / branch name. Not verified live: the pull request page itself (its toolbar selector is unexercised), and the Actions tab's own landing page. A userscript manager is installed in the browser I used, but it runs the released version and I couldn't repoint it at this build, so all of the above was injected by hand rather than loaded as a userscript.
One thing to know before merging:
yarn install --immutablealready fails onmain- the rootpackage.jsonpinstypescriptat~6.0.3whileyarn.lockresolves~7.0.2. That predates this branch and nothing here touches either file, but it will show up in CI.Co-Authored-By: Claude noreply@anthropic.com