B3.Blicks.Admin.UI 2026.8.6.1
B3.Blicks.Admin.UI
The in-app Blicks Admin page — an operator view a host Shell mounts at /_blicks/admin. Read-only by
default (slice 1); a host that registers a write path (slice 2) gets browse/assign/save with pre-flight
gating too.
Slice 1 (read-only)
- Region 1 — current selection. Each pinned Blick's id, version, status, and where the pin came from
(relay vs. appsettings fallback). Wired from a host-implemented
ICurrentBlickSelection; a config-backed default readsBlicks:SelectedVersions. - Region 2 — registry catalog. Every Blick in the registry (not just pinned ones — see slice 2), with
pin-target versions read per Blick (
GET /api/v1/blicks/{id}). A registry that can't be reached renders "unverifiable" — it never throws. - Region 3 — pre-flight. Picking a version link runs
SharedManifestPreflight.Validateagainst the Shell's shared-platform manifest and reports OK / would-be-refused / unverifiable.
With no write path registered, the page is exactly this — no save, no restart button.
Slice 2 (write path)
Registering an IBlickSelectionCommands before calling AddBlicksAdmin turns on assign/change/remove/save:
builder.Services.AddSingleton<IBlickSelectionCommands>(sp => new YourSaveImplementation(...));
builder.Services.AddBlicksAdmin(builder.Configuration);
- Region 2's catalog rows get an Assign action per pin-target version; an already-pinned Blick shows an Assigned badge. Region 1's running-selection rows get a Remove action.
- Edits round-trip through the page's own
pendingquery/form value (no server-side session) and show up in Region 1 as an unsaved changes panel — a diff table (Blick / running / pending / live pre-flight outcome) plus Save and Discard. - Save re-runs pre-flight for every CHANGED entry:
WouldBeRefusedblocks the save and shows the reasons;Unverifiable(registry unreachable) saves anyway with a prominent warning;OKsaves. It callsIBlickSelectionCommands.Savewith the FULL desired selection (not a delta). - After a successful save, Region 1 shows the pending-vs-running difference honestly — the write path only
persists a desired selection; nothing here restarts the process. A host's
Saveimplementation decides how (or whether) to apply it — seeTester.Shell.Blicks.BlickUpdaterfor a reference implementation that just writes a file and leaves the restart to the operator.
No default is registered for IBlickSelectionCommands — its absence IS the read-only fallback, matching
slice 1 exactly.
Wiring it into a Shell
builder.Services.AddBlicksAdmin(builder.Configuration);
// ...
app.MapBlicksAdmin();
Off by default — set BlicksAdmin:Enabled to true to mount the page. The route (and, when a write path is
registered, its /working, /discard, /save POST endpoints) is gated by the
BlicksAdminAuthorization.PolicyName authorization policy, which the Shell MUST define via
AddAuthorization(o => o.AddPolicy(BlicksAdminAuthorization.PolicyName, ...)). If the Shell never defines
it, ASP.NET Core's authorization middleware refuses every request for the missing policy — fail-closed, never
fall open. Every POST binds its form data via [FromForm], which ASP.NET Core automatically requires a valid
antiforgery token for once app.UseAntiforgery() is in the pipeline — the page's forms carry <AntiforgeryToken />.
Configuration (BlicksAdmin: section): Enabled, RegistryBaseURL, RegistryAPIKey.
To get a real current-selection view and a meaningful pre-flight check, register your own
ICurrentBlickSelection and a populated SharedPlatformManifest singleton before calling AddBlicksAdmin —
otherwise the page falls back to the config-backed defaults (an empty manifest is a safe no-op, matching
ResolverOptions.SharedPlatform's own default).
No packages depend on B3.Blicks.Admin.UI.
.NET 10.0
- B3.Common.SimpleLogging (>= 2026.7.26.4)
- NuGet.Protocol (>= 6.13.2)
| Version | Downloads | Last updated |
|---|---|---|
| 2026.8.6.1 | 6 | 8/6/2026 |