Image widget backed by the standalone SK Image plugin - #1120
Open
dillan wants to merge 11 commits into
Open
Conversation
Port the Image display widget, the shared-library picker in widget config, and the Settings -> Media image-cache card onto the current master. Image storage, processing, and caching now live in the standalone SK Image Signal K plugin (available in the app store); the widget talks to its REST API through ImageAssetService. Declare sk-image in signalk.recommends so the Signal K App Store offers to install it when KIP is installed or updated. Registered the widget with a lazy component loader to match the current widget.service structure.
These tests intentionally fail. They pin the Image widget to the plugin's crew-reachable /signalk/v1/api/sk-image mount instead of the /plugins/sk-image alias. On a secured Signal K server the server admin-gates every /plugins/* route, so the alias 401/403s ordinary crew (and the native <img> element, which sends no auth header) even for reads — making the widget unusable for its intended audience. Also covers a configured URL that already carries a /signalk suffix, which must not double up. The resolver fix follows.
Resolve the plugin base against the server's /signalk/v1/api/<id> mount instead of the /plugins/<id> alias. signalk-server admin-gates every /plugins/* route on a secured server, so the alias returned 401/403 to ordinary crew — and to the native <img> element, which sends no auth header — even for reads, leaving the widget unusable for its intended audience. The /signalk/v1/api mount is public for reads and only gates writes on a read-write/admin principal. Add a shared stripToServerRoot() helper and use it in both resolvePluginBaseUrl and PluginConfigClientService.toServerUrl, so a configured URL that already ends in /signalk (which the connection service accepts) no longer produces a doubled or misrooted path for image and plugin-admin requests.
The add-widget dependency check treated any failed plugin-state lookup as
"installed but disabled" and prompted to enable it. On a secured server the
/plugins/{id} state API is admin-only, so ordinary crew got a 401/403, were told
the required plugin was disabled, and were dead-ended with an "enable" prompt
they have no permission to satisfy.
Now an auth-required/forbidden result is treated as "can't verify" and does not
block the add: the widget's own endpoints are crew-reachable and render (or
surface an install hint) on their own. Installed-but-disabled and not-found keep
their existing prompt behavior.
On a secured server a logged-in read-only account can view the library but not change it. A denied upload/delete now returns 403, so tell the user their account is read-only and to ask an admin for read-write access, instead of the old "check your connection" message that blamed the network for a permissions problem. Also point the "library won't load" 404 at installing the SK Image plugin from the App Store, and make the viewer's unavailable message say the image may have been removed or the server is unreachable.
The Image widget starts with a container width of 0, and an unknown width snaps to the largest (2560px) variant — so every image widget fetched a full-res copy on first paint, then replaced it once the real width was measured. Request the smallest variant until the first measurement instead; it's cheap and upgrades on resize. Make the asset service's base URL and discovered width allow-list signals, so a URL built inside a reactive computed (the widget) recomputes when the server's GET /config list arrives instead of locking to the built-in fallback.
The Image widget's help doc and changelog described image serving as if it were built into KIP. Say plainly that images are stored and served by the separate SK Image Signal K plugin (1.4.0+), that KIP recommends it so the App Store offers to install it, and that the plugin needs Node.js 24+ on the server. Clarify that changing images needs write access (a read-only account can view but not edit). Also make the help doc's image paths base-relative (assets/help-docs/img/...) instead of parent-relative, per the mxtommy#1056 guard added upstream.
The harness described the pre-split, integrated model — build one kip.tgz that bundles the image server, and read images from /plugins/kip/images. That architecture no longer exists. Install the standalone sk-image plugin from npm alongside the KIP webapp, seed and read the library at /signalk/v1/api/sk-image, enable sk-image in the baked config, and note the Node 24+ requirement. Document how to verify the secured-server role behavior (anon/read-only can view, read-only gets 403 on upload, admin manages) — that multi-role check is manual; only the open screenshot server is scripted here.
stripToServerRoot ran a chain of ../signalk suffix replacements over the whole URL, so a server addressed as http://signalk (e.g. behind a reverse proxy on port 80) collapsed to http:/ — breaking every plugin and image request. Parse off the scheme+host first and strip the /signalk[/vN[/api]] segment from the path only, so the authority is never touched. Adds tests for the signalk-host and reverse-proxy-subpath cases. Also spell out that a missing library can be installed OR enabled, since a disabled plugin 404s the same as an uninstalled one.
SK Image 1.5.0 lowered its Node floor to 22.13. Point the help doc, changelog, and screenshot harness at 1.5.0+ and Node.js 22.13+, and soften the harness Dockerfile note since most signalk-server images already run Node 22+.
…k-image # Conflicts: # CHANGELOG.md # package.json
dillan
marked this pull request as ready for review
July 7, 2026 04:14
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.
Adds an Image display widget to KIP. Image storage and processing now live in the standalone SK Image Signal K plugin (published, in the App Store); KIP ships only the widget, a shared-library picker, and a Settings → Media cache card, all talking to the plugin's REST API.
This supersedes the earlier three-PR split (#1080 server, #1081 client, #1082 config UI): the server engine became the standalone
sk-imageplugin, so there's nothing server-side left to land in KIP. Those three can be closed in favor of this one.What's in it
ImageAssetService+ a plugin-URL resolver that target the plugin's crew-reachable/signalk/v1/api/sk-imagemount and discover the variant-width list from the plugin'sGET /config.sk-imageadded tosignalk.recommendsso the App Store offers to install it when KIP is installed/updated.Notable correctness details
/plugins/*route, so a/plugins/sk-imagepath would 401/403 ordinary crew — and the native<img>, which sends no auth header — even for reads. The widget uses/signalk/v1/api/sk-image, where reads are public and only writes need a read-write/admin principal.Requirements
Tests
Unit tests cover the mount resolution (incl. a
/signalk-suffixed configured URL and a host literally namedsignalk), the auth-aware dependency check, the read-only 403 copy, and the first-paint variant. Full suite green (492), lint clean, production build + plugin build OK.