sac-ae-snap-report-widget

AE Snap Report — SAC Custom Widget

A single custom widget for SAP Analytics Cloud that renders the “Traditional Snap Report” dashboard: a high-level daily view of Annual Enrollment (AE) progress. Built the same way as the Hello World POC — a widget.json manifest plus a web-component JS file — but with real dashboard content instead of a single label, and three real data bindings instead of none.

Before wiring real data, read DATASPHERE_VIEW_SPEC.md — it defines exactly what Datasphere view(s) this widget expects, tracing every field back to the already-approved SAP CDS views it reuses (no new business logic invented). It also documents two open items that are not yet resolved (church membership YoY count source, Synod/Region data access) — the widget itself surfaces these as a standing notice until they’re settled.

Files

Status of this build

Known limitation: no internal interactivity in View mode

Confirmed by testing directly in SAC (Optimized story): the widget’s internal <button>/<select> controls receive click/change events normally in Edit mode, but View mode delivers none of them — confirmed via a completely silent DevTools console on click (no error, no log, nothing), ruling out a JS bug. This isn’t something fixable from the widget’s own code — SAC’s Optimized-story View mode apparently doesn’t forward internal DOM events into a custom widget’s shadow DOM, at least not in this configuration.

Consequence, resolved 2026-08-28: both the dark/light theme toggle and the Status/Synod-Region filter dropdowns were removed from the widget entirely, rather than ship controls that only work in Edit mode. The widget now renders light theme only, with no in-widget filter UI at all — it’s a pure display component that renders whatever data currently arrives through its three data bindings via onCustomWidgetAfterUpdate (confirmed working correctly end-to-end, independent of this issue).

Filtering now happens entirely in SAC, not in the widget: place a native Input Control on the Story, wire it to the underlying data source(s), and SAC handles re-querying and pushing the filtered result set into the widget’s bindings — no custom-widget-side code needed for that, and it isn’t subject to the View-mode limitation above since it’s SAP’s own supported control, not something drawn inside our shadow DOM. Worth raising the underlying platform behavior with SAP support/community separately (see the issue writeup shared alongside this doc), but no need to block on that to move forward.

Same reasoning applies to the employer-detail download feature (see BUILD_PLAN_VWEMPLOYERSAVES.md, “Download experience”): it’s a native SAC Table widget with SAC’s own built-in export, placed on the Story alongside this widget — not a button inside it. Nothing in this repo (main.js, widget.json) changes to support it.

1. Preview locally (no SAC needed)

python -m http.server 8420 --directory sac-ae-snap-report-widget

Then open http://localhost:8420/preview.html. You should see the full dashboard rendered from the mock data baked into main.js.

2. Host main.js and icon.svg

Same pattern as the Hello World POC — host this folder on GitHub Pages (Settings > Pages, source: branch main, folder /root). widget.json already points at:

If main.js changes, recompute the integrity hash in widget.json:

openssl dgst -sha384 -binary main.js | openssl base64 -A

3. Register the widget in SAC

  1. System > Custom Widgets > Add Custom Widget (+).
  2. Upload widget.json.
  3. Name it (e.g. “AE Snap Report”) and save.

4. Build the Datasphere views and SAC model

Follow DATASPHERE_VIEW_SPEC.md end to end — do not skip its two open items. Once DS_AE_SNAP_REPORT (or the source-aligned views individually) exist in Datasphere:

  1. Build a SAC model on top.
  2. Create three queries/data sources matching the shapes in DATASPHERE_VIEW_SPEC.md section 2 (employer status, daily counts, YoY).

5. Bind and place in a Story

  1. Drag the widget onto a Story/Analytic Application canvas.
  2. In the widget’s data-binding panel, bind employerStatus, dailyCounts, and yoyComparison to the three queries from step 4.
  3. Set the Story’s refresh interval (real-time is a stretch goal — see DATASPHERE_VIEW_SPEC.md section 4 — start with scheduled refresh).
  4. Confirm the tiles/chart match real numbers, not the mock data.

Next steps beyond this build