Skip to content

Show plugin release notes in-app on the Plugin Manager - #2932

Merged
darylc merged 4 commits into
FalconChristmas:masterfrom
focusedonsound:feat/plugin-card-release-notes
Sep 23, 2026
Merged

darylc merged 4 commits into
FalconChristmas:masterfrom
focusedonsound:feat/plugin-card-release-notes

Conversation

@focusedonsound

@focusedonsound focusedonsound commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds a release-notes entry point to plugin cards (icon in the bottom-right of the card's action row, clustered with the existing GitHub stats badge via the same ms-auto pattern) and to the plugin detail modal's Home/View Source/Report-a-Bug link list.
  • Gated on an explicit releaseNotesStyle field in pluginInfo.json, not "is this GitHub-hosted" (see discussion below) — none (default/absent, no icon), gitRelease, gitHistory, or script.
  • Clicking it opens a modal showing the plugin's release notes in-app, in whichever form it declared, rather than sending the user out to GitHub:
    • gitRelease: the plugin's latest GitHub Release. Backend: GET /api/plugin/{RepoName}/releaseNotes proxies https://api.github.com/repos/<repo>/releases/latest server-side (same idea as the existing GitOSReleaseNotes(), generalized to an arbitrary repo instead of hardcoded to FalconChristmas/fpp), TTL-cached the same way GetPluginGitHubStats()'s cache already is. Rendered with the same narrow, dependency-free markdown-to-HTML converter about.php already uses for FPP's own release notes (HTML-escapes first, then only ever adds back a fixed whitelist of tags for a fixed whitelist of markdown constructs).
    • gitHistory: the commits between the installed clone's HEAD and origin/<branch> — read directly from the plugin's own repo, no GitHub API call, works for any git-hosted plugin whether or not it tags releases. Reuses PluginCurrentBranch() and the same delimited git log format changelog.php uses for FPP's own commit history.
    • script: runs the plugin's own scripts/fpp_releasenotes.sh and shows its stdout as plain (HTML-escaped) text — for plugins whose update-worthy changes aren't in the git log at all (the same fpp_update_check.sh/fpp_upgrade.sh escape hatch PluginHasUpdates() already accommodates for plugins like Pulshmesh/FPPMon).
  • The release-notes trigger dispatches through the existing data-plugin-action delegated click handler, consistent with Install/Update/Uninstall. Guards against stacking a second Bootstrap modal when triggered from inside the already-open plugin detail modal.

Why the gating changed since the screenshots above

@dkulp pointed out almost no plugin has a tagged GitHub Release today, so gating on "is this GitHub-hosted" meant showing an icon that's a dead end for nearly everyone who clicks it, and shouldn't need a round trip to find that out. @jessica12ryan's follow-up (commit list instead) and @dkulp's response (some plugins' updates aren't git commits at all — fpp_update_check.sh/fpp_upgrade.sh-driven components) converged on: make it author-declared per-plugin via pluginInfo.json, not auto-detected. This PR implements exactly the "releaseNotesStyle": "none"|"gitRelease"|"gitHistory"|"script" shape @dkulp proposed, with all three non-none styles wired up.

Cross-repo note for @darylc: releaseNotesStyle needs a matching addition to pluginInfo.schema.json / PLUGININFO_FORMAT.md in fpp-plugin-Template (and fpp-data's vendored copy of the schema that lint_plugin.py validates against) — neither lives in this repo, so I didn't touch them. Happy to put up that PR myself once you've had a look at the shape here, or if you'd rather add it yourself to match how you structured the privacy block, that works too.

Test plan

  • Verified on a live FPP 10 (master) install: gitRelease endpoint returns the trimmed release object for a repo with real releases, and a clean 404 for a repo with no GitHub Releases published.
  • Confirmed input validation on the old ?repo= design; now superseded by reading the installed plugin's own pluginInfo.json server-side, so there's no client-supplied repo/style to validate at all.
  • Confirmed TTL caching: repeat gitRelease calls are served from the cache file rather than re-hitting GitHub.
  • Confirmed in-browser: the card icon and the detail modal's "Release Notes" link both open the modal correctly for gitRelease, the "no releases" case shows a friendly message with a GitHub fallback link, and triggering it from inside the already-open detail modal does not stack two modals.
  • Confirmed the markdown converter renders headers/bold/lists correctly against a real release body.
  • gitHistory and script styles are implemented but not yet exercised against a real plugin with that style declared (no plugin declares releaseNotesStyle yet, pending the schema addition above) — will verify against a test plugin once that's in place, but wanted this up for review now given the direction was already confirmed with @dkulp.

focusedonsound and others added 2 commits September 9, 2026 12:12
Plugin cards (and the detail modal's Home/Source/Bug link list) had
no way to see what changed in an update without leaving FPP for the
plugin's own repo. Adds a release-notes link, auto-derived from the
plugin's GitHub srcURL (reusing GitHubRepoOf(), the same owner/repo
derivation the existing GitHub-stats badge uses) as
https://github.com/<owner>/<repo>/releases -- no new pluginInfo.json
field, works immediately for every existing GitHub-hosted plugin.

Rendered inline in the card's bottom action row via the same ms-auto
pattern the GitHub-stats badge already uses (so the two cluster
together at the trailing edge whether or not stats data is present),
and shown at every UI level -- unlike the stats badge, this needs no
API call, so there's no reason to gate it behind Advanced/Developer.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjuzBZvDeLNNaGX7j9mC8p
Replaces the plain external link with an in-app modal, mirroring how
about.php already shows FPP's own OS release notes: a new
GET /api/plugin/releaseNotes endpoint proxies GitHub's releases API
server-side (same TTL-cache convention as the existing GitHub-stats
endpoint, and keeps api.github.com out of the CSP), and the frontend
renders the release body with the same narrow, dependency-free
markdown-to-HTML converter about.php uses -- HTML-escape first, then
only ever add back a fixed whitelist of tags for a fixed whitelist of
markdown constructs, so nothing in a plugin author's release text can
inject arbitrary markup.

The card icon and the detail modal's "Release Notes" link now both
dispatch through the existing data-plugin-action click handler
(action: "releaseNotes") instead of being a plain <a href>, since
opening a modal needs to run JS, not navigate. Guards against stacking
a second Bootstrap modal when triggered from inside the already-open
detail modal.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjuzBZvDeLNNaGX7j9mC8p
@OnlineDynamic

Copy link
Copy Markdown
Contributor

could you please add some screenshots to the PR so we can see what it does quickly

@focusedonsound

Copy link
Copy Markdown
Contributor Author

Below are a few screenshots of the suggested addition of release notes to inform plugin users of the changes made without sending them away from FPP.

release_notes_3 release_notes_2 release_notes_icon

@dkulp

dkulp commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

I believe this would need to be opt-in of some sort via a flag in the pluginInfo or similar. Almost none of the plugins would have any sort of tagged release (at this point) on GitHub. Example, the fps-brightness plugin has 0 releases. Thus, it should not be shown and really, shouldn't involve extra round trips to 404 or whatever when we can know ahead of time not to do it.

@focusedonsound

Copy link
Copy Markdown
Contributor Author

Totally fair point — you're right that most plugins won't have tagged releases yet, and I don't want this showing an icon that just leads to a dead end for people.

Good news is this repo already solves basically this exact problem for the GitHub stats badge (open issues/PRs) — it batches all the installed plugins into one cached lookup instead of hitting GitHub per-plugin. I can extend that same batch/cache pass to also check "does this repo actually have a release" and only show the icon when the answer is yes. So no manifest flag needed, no extra round trips, and it can't go stale like a flag would if someone forgets to update their pluginInfo.json.

Also just want to call out why I think this is worth having at all: right now if someone wants to see what changed in a plugin update, they have to leave FPP, go to the GitHub repo, and dig through releases/commits — most users are never going to do that, they'll just update blind or not update at all. Being able to see "here's what's new" right in the Plugin Manager keeps people in the app instead of bouncing them out to GitHub, which I think matters more as more plugins start actually using releases for this.

If you think it's worth moving forward I will push an update handling the has-release check properly. With all of the changes to the Plugin Manager, I thought this was worthwhile to get people accustomed to providing.

@jessica12ryan

jessica12ryan commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

I like this idea, but not how it's laid out. I don't mean to give criticism, but I want to offer my honest feedback. As Dan said, most plugins don't have release notes. To include this function for only a handful of plugins I don't think is a practical execution.

Here's what I believe would work:
In FPP, you can click on the number of updates available and see the list of commits. The commit number and title of commit, so instead of opening GitHub, you can easily view the changes to FPP.
A similar approach would be very nice where if you click a button, you get the list of commits for that plugin. This takes any additional work off the plugin developers, and allows the commit tracking to be displayed directly from GitHub. Every plugin would then have the ability to show a list of commits before a user installs an update. We wouldn't be singling out plugins that only have release notes, and we wouldn't be adding any additional unnecessary work for plugin developers.

@dkulp

dkulp commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

That doesn't entirely work either.... some plugins have updates, but may not necessarily have any GitHub commits. Plugins can have a scripts/fpp_update_check.sh (and associated scripts/fpp_upgrade.sh) that drive the upgrade process for that plugin. Thus, plugins that have components (like pulshmesh, fppmon, etc...) that are not part of the git repository can check for updates in those areas. As I said, I really think this needs to be somehow driven in pluginInfo. It can be something like a simple flag on the version range of something like:

"releaseNotesStyle": "none|gitRelease|gitHistory|script"

(script would call an option scripts/fpp_releaseanotes.sh so the plugin can generate as needed).

@focusedonsound

Copy link
Copy Markdown
Contributor Author

@dkulp this is the approach I intend to take to close this out — wanted to confirm with you specifically before I put the work in:

Add releaseNotesStyle: none|gitRelease|gitHistory|script to pluginInfo.json as you proposed, gate the icon on that instead of "is this GitHub-hosted," and wire up gitHistory (commit list) and script (calls scripts/fpp_releasenotes.sh) alongside the existing gitRelease path.

Is this the right direction, or did you have something more specific in mind for how gitHistory/script should behave?

@darylc
darylc self-requested a review September 14, 2026 06:59
focusedonsound and others added 2 commits September 15, 2026 14:51
…osted"

Implements dkulp's proposed approach from PR review: almost no plugin has
a tagged GitHub Release today, so showing the release-notes icon on
every GitHub-hosted plugin (the original design) meant showing a dead
end for nearly everyone who clicked it. Gate on a new pluginInfo.json
field instead:

  "releaseNotesStyle": "none" | "gitRelease" | "gitHistory" | "script"

- gitRelease: unchanged behavior -- latest GitHub Release, proxied and
  TTL-cached server-side.
- gitHistory (new): the commits between the installed clone's HEAD and
  origin/<branch>, read directly from the plugin's own repo -- no GitHub
  API call, works for any git-hosted plugin whether or not it tags
  releases. Reuses PluginCurrentBranch() and the same delimited git-log
  format changelog.php already uses for FPP's own commit history.
- script (new): runs the plugin's own scripts/fpp_releasenotes.sh and
  shows its stdout as plain (HTML-escaped) text, for plugins whose
  update-worthy changes aren't in the git log at all -- the same
  fpp_update_check.sh / fpp_upgrade.sh escape hatch PluginHasUpdates()
  already accommodates.

The endpoint moved from `GET /api/plugin/releaseNotes?repo=owner/name`
(client-supplied, gitRelease-only) to `GET /api/plugin/{RepoName}/releaseNotes`
(server reads the installed plugin's own pluginInfo.json, dispatches on
its declared style) -- the server no longer trusts a client-claimed repo
or style, and the same entry point now serves all three modes.

The icon (card action row and the detail modal's link list) is gated on
PluginReleaseNotesStyle(data) !== 'none' instead of GitHubRepoOf(data),
so an undeclared plugin shows nothing rather than a link to a 404.

Cross-repo note: `releaseNotesStyle` needs a matching addition to
pluginInfo.schema.json / PLUGININFO_FORMAT.md in fpp-plugin-Template
(and fpp-data's vendored copy of the schema, used by lint_plugin.py) --
neither lives in this repo. Flagging for darylc rather than editing a
repo I don't maintain.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AE12rwWGhsJsyfENBXpBs5
@focusedonsound

Copy link
Copy Markdown
Contributor Author

@dkulp — pushed the approach you proposed. `releaseNotesStyle` (`none`/`gitRelease`/`gitHistory`/`script`) now gates the icon entirely; a plugin that hasn't declared one shows nothing. All three non-`none` styles are implemented server-side (`gitHistory` reads local git history against `origin/`, no GitHub call; `script` runs `scripts/fpp_releasenotes.sh`) and client-side (a renderer per style in the same modal). Let me know if `gitHistory`/`script` aren't quite what you had in mind, or if there's a shape for the `script` output you'd rather see (currently plain stdout, HTML-escaped, no markdown interpretation).

@darylc — this needs a schema companion: `releaseNotesStyle` should get added to `pluginInfo.schema.json`/`PLUGININFO_FORMAT.md` in `fpp-plugin-Template`, and mirrored into `fpp-data`'s vendored copy so `lint_plugin.py` doesn't reject a plugin that declares it (same situation as `additionalProperties: false` rejecting anything undeclared, which the recent `privacy` block addition also had to account for). Want me to put up that PR, or would you rather add it yourself to keep it consistent with how you structured `privacy`? Either way works for me — just don't want to step on how you want that repo organized.

PR description updated with the full rundown. Rebased onto current master (this had drifted ~130 commits behind) and resolved conflicts against your `privacy`/`PrivacyRowHtml` work — kept both rows on the card.

@darylc

darylc commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

@focusedonsound I'm still backlogged with FPP asks, I have started working towards this - the fpp-plugin-Template work is published FalconChristmas/fpp-plugin-Template@2363504 and the fpp-data work is done but not committed. That will go out soon in conjunction with the notification of the privacy fields for plugins.

@darylc
darylc merged commit 2275e1b into FalconChristmas:master Sep 23, 2026
darylc added a commit that referenced this pull request Sep 23, 2026
- Link only for installed plugins, and only when there is something to
  show; the style is read from the pending update's pluginInfo.json.
- gitRelease: uses the configured GitHub token, tells "no release" apart
  from "repo not visible", serves the last good copy when GitHub fails.
- gitHistory: pending commits plus recent installed history.
- script: only the installed script runs, with a hard deadline, process
  group kill, 64 KiB cap and a clean environment.
- Errors carry a message the dialog shows; uses the shared markdown
  renderer; F1 help entry; openapi.json regenerated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants