Skip to content

Image assets (3/3): widget config UI + settings image-cache card - #1082

Closed
dillan wants to merge 14 commits into
mxtommy:masterfrom
dillan:feat/image-assets-config-ui
Closed

Image assets (3/3): widget config UI + settings image-cache card#1082
dillan wants to merge 14 commits into
mxtommy:masterfrom
dillan:feat/image-assets-config-ui

Conversation

@dillan

@dillan dillan commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Image assets (3/3) — widget config UI + settings image-cache card

Part 3 of 3 adding user-uploaded image assets to KIP dashboards. This PR adds the config UI for the Image widget (upload, shared-library picker, display options) and a settings card to manage the on-disk image cache.

Stacked on PR 2 (client). It builds on the ImageAssetService and Image widget from PR 2, so this branch contains PR 2's two commits as well — review/merge PR 2 first and this PR's diff collapses to just the config-UI changes below. (GitHub shows the cumulative diff because both target master.)

What it does

  • image-source-setup widget-config sub-component (wired into the widget config Display tab via @else if (widgetConfig?.image)):
    • Upload with client-side guards (≤10 MB + accepted-type check) and an upload progress bar; clear error messages mapped from the server (401 not-logged-in, 413 too-big, 415 unsupported).
    • Shared library gallery — thumbnails from list() to reuse an image across widgets/dashboards; select sets the widget's imageId; per-item delete. The selection highlight is signal-driven so it updates correctly under zoneless change detection even from async upload/delete callbacks, and gallery refreshes are sequence-guarded against out-of-order responses.
    • Display options: scaling (Fit / Fill), alt text, and a background color picker with a Transparent toggle.
  • Settings → Configurations → Image Cache card — shows the on-disk cache size + file count with Refresh and Purge (confirmation dialog). Purging removes generated variants only; originals are kept and variants regenerate on demand.
  • Help doc (imagewidget.md + menu entry) and a CHANGELOG entry.

Tests

image-source-setup.component.spec.ts (ensure/preserve controls, ≤10 MB + type validation incl. HEIC-by-extension, gallery load, select/delete, upload success + 401 error mapping, transparent toggle, signal highlight). config.component.spec.ts extended (cache size formatting, Unavailable when not ready, purge-after-confirm, no-purge-when-declined). Vitest/zoneless. Lint clean; app builds.

Status / gates

  • App build clean; ng lint clean; image-source-setup (13 tests) + config-card additions pass. An independent adversarial review of this UI found two zoneless-reactivity issues that are fixed here (signal-driven gallery highlight; sequence-guarded list refresh).

Stacking


📚 3-PR stack (review/merge in order)

  1. Image assets (1/3): Signal K plugin — secure upload, processing, worker pool, cache #1080 — Signal K plugin: secure upload, processing, worker pool, cache (server)
  2. Image assets (2/3): Angular client — ImageAssetService + Image widget #1081 — Angular client: ImageAssetService + Image widget
  3. Image assets (3/3): widget config UI + settings image-cache card #1082 — Widget config UI + settings image-cache card

PR 2 needs PR 1 at runtime; PR 3 is stacked on PR 2. Together they add the full image-assets feature.

You are viewing PR 3 of 3.

Screenshot 2026-06-24 at 2 37 10 PM Screenshot 2026-06-24 at 2 37 22 PM Screenshot 2026-06-24 at 2 37 56 PM Screenshot 2026-06-24 at 2 40 48 PM

resolveKipPluginBaseUrl() extracts the <server>/plugins/kip/ resolution (mirroring
kip-series-api-client) and snapImageWidth() snaps a container width (x DPR) to the
server's variant allow-list so the client requests stable, cache-friendly URLs.

ImageAssetService wraps the plugin endpoints: upload (multipart FormData with progress),
list, delete, cacheStats, purgeCache, and urlFor(id, cssWidth, dpr) for the widget.
Requests are auto-authenticated by the JWT interceptor. 9 vitest cases green.
dillan added 8 commits June 24, 2026 05:05
New widget-image renders a selected image (by id) via ImageAssetService, scaled to fit the
widget with object-fit (contain/cover) over a configurable background that defaults to
transparent so the dashboard shows through. It tracks its container width with the existing
kipResizeObserver directive and requests a server variant matched to that width (x DPR) so a
small widget never downloads a full-resolution image. Shows an empty state when nothing is
selected. Registered in WidgetService (component map + Component-category definition); adds the
`image` config block to IWidgetSvcConfig. 3 vitest cases (empty state, render+object-fit,
background default/override).
Lets users upload an image (client-side 10 MB + type guard, progress),
pick or delete from the shared library, and set the scaling, alt text,
and a background color or transparent background for the Image widget.
Wired into the widget config Display tab for widgets that expose an
image config group.
Shows the on-disk size of generated image variants and a Purge button
(with confirmation). Purging keeps originals; variants regenerate on
demand. Refresh re-reads the size after viewing images.
Splits the thumbnail into a select button and a sibling delete button so
both are keyboard-focusable and avoid an invalid nested-button structure.
Make the gallery selection a signal so the highlight updates under
zoneless change detection even when set from async upload/delete
callbacks, instead of relying on an incidental signal write. Add a
sequence guard so a slow image list() response can't overwrite a newer
one.
Matches the sibling image-source-setup component and the project's
takeUntilDestroyed convention. HttpClient one-shots self-complete, so this
is convention-consistency, not a leak fix.
Add a small horizontal gap between the Refresh and Purge buttons on the
settings image-cache card (the footer is text-align:end, not flex).
@dillan
dillan force-pushed the feat/image-assets-config-ui branch from 0e3e544 to c269267 Compare June 24, 2026 10:06
@dillan
dillan marked this pull request as ready for review June 24, 2026 11:29
dillan added 5 commits June 27, 2026 00:06
The image cache card was placed on the Configurations tab, which is for KIP
configuration management (backup, restore, import, export). Move it to a new
Media tab, placed before Configurations, so the image cache lives with media
concerns rather than config management.

Extracts the image-cache logic into a SettingsMediaComponent (with its own
spec) and removes it from SettingsConfigComponent. Updates the Image widget
help doc to point at Settings → Media → Image Cache.
The Image widget had no icon in the widget picker (icon was empty). Add an
"imageWidget" landscape/image glyph to the shared SVG icon set and reference
it from the widget definition so the widget shows a recognizable icon.
Acts on a UX audit of the Image widget.

Safety / state
- Deleting an image now asks for confirmation, naming the shared, boat-wide
  scope — a single tap previously removed it from every display with no undo.
  The delete control moved to a 44px button in a footer row, out of the select
  tap zone.
- The gallery distinguishes a failed library load from a truly empty one
  (loading spinner, error + Retry), so an unreachable server no longer reads
  as "no images". The live widget shows "Image unavailable" instead of a broken
  glyph when its image disappears.
- Upload and delete share one status-aware error mapper.

Accessibility
- Thumbnails expose selection (aria-pressed) and group semantics, visible
  keyboard focus, a named delete label, and a live region announces
  upload/delete status. "Alt text" is now "Description" with a hint; thumbnails
  are captioned with the image name and sorted newest-first.

Clarity / theming
- Plainer copy throughout (errors, the Fill option, the cache card's
  "Clear cache"). Touch-safe color control. The opaque background seeds from
  the active theme instead of hardcoded black, transparent diagrams sit on a
  neutral checkerboard, and a live preview shows the chosen fit/background.

Updates the component specs (delete confirmation, 401 mapping, gallery error
state, newest-first sort, theme-seeded background).
Relabels the help text to match the new UI ("Alt text" -> "Description",
"Purge" -> "Clear cache") and refreshes the screenshots: the redesigned
config dialog (shared "Boat image library" with thumbnails, captions and
footer delete) and the Media -> Image Cache card showing a real cache size.

Also points the help menu at the renamed image-widget.md and gitignores the
Playwright MCP working dir.
Spins up an open (no-login) Signal K server with the integrated KIP image
plugin + webapp, seeded with realistic marine diagrams, so the Image widget
help screenshots (gallery, thumbnails, real cache size) can be reliably
re-captured as the UI evolves.

The image feature spans three branches (server/client/config-ui); the README
documents merging the server branch and `npm pack` to produce the kip.tgz the
Dockerfile installs (which resolves native deps like sharp for the container).
@dillan

dillan commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #1120 (consolidated). The config UI + Settings → Media cache card land there, re-pointed at the standalone sk-image plugin. Closing.

@dillan dillan closed this Jul 6, 2026
@dillan
dillan deleted the feat/image-assets-config-ui branch July 6, 2026 19:42
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.

1 participant