Beyond the panel
Extending
A library - or an app - can add to BevTools: panels, state providers, diagnostic rules, palette commands, value
formatters and timeline events of its own. This site registers such an extension,
DemoBevToolsExtension, and every part of it is visible in the panel right now.
Timeline events of your own
Code that does work BevTools cannot see - a sync, a cache refresh, a background job - can put it on the timeline
through IBevToolsTimeline, a scoped service. Each button below records an Inventory sync
with BeginActivity, which takes its duration when the scope ends.
@inject IBevToolsTimeline Timeline using (Timeline.BeginActivity("sync", "Inventory sync", $"{ms} ms of simulated work")) { await Task.Delay(ms); }
The Timeline shows each sync as a custom entry with its duration, caused by the click
that started it (the custom chip filters them). Record and Complete do the same
in two steps, and IsEnabled says whether to build an event at all.
What the demo's extension adds
- A panel: the Store tab, after the built-in ones. It lists who listens to
FilterState- open the Products page, show and hide the price alert, and one more lambda in PriceAlert.OnInitialized stays subscribed each time. It inheritsBevToolsTab, so it re-reads whenever the panel refreshes, and its renders and clicks never count as the app's. - A state provider: State → FilterState, marked extension.
FilterStateknows nothing about BevTools; an adapter reads it and names each change (SetQuery,SetCategory,SetMaxPrice,Notify), so typing on the Products page builds a history with diffs. - A diagnostic rule: demo.slow-sync turns a sync over a second into a finding - press Run a slow sync and open Diagnostics. It appears in the Rules table with the built-in ones.
- Two commands: CtrlK, then
>demoor>cart→ Show the demo store and Copy the cart as Markdown, under Demo store. Without the>the palette searches components, events and services. A command can show a panel, select a component or an event, notify, and hand text to the browser (CopyTextAsync,DownloadTextAsync). - A value formatter for
Product: select aProductRow, or open State → CartState, and a product reads Rustic Keyboard 2 · $83.99 instead of a record to expand.
About → Session → Extensions names every extension that is loaded: Demo store, and Blazor Server circuits - the Circuit panel, its rules and command are themselves an extension.
Writing one
A library references Bit.BevTools, implements IBevToolsExtension and is added to the
options. This is the demo's, shortened; the whole file is Demo/Client/Extension/DemoBevToolsExtension.cs.
public sealed class DemoBevToolsExtension : IBevToolsExtension { public string Name => "Demo store"; public void Configure(IBevToolsExtensionBuilder builder) => builder .AddPanel(new BevToolsPanelDescriptor("demo-store", "Store", typeof(DemoStorePanel))) .AddStateProvider(services => new FilterStateAdapter(services.GetRequiredService<FilterState>())) .AddDiagnosticRule(new SlowSyncRule()) .AddCommand(new ShowStoreCommand()) .AddCommand(new CopyCartCommand()) .AddValueFormatter(typeof(Product), v => v is Product p ? $"{p.Name} · {p.Price:C}" : null); } // Program.cs of every host that runs BevTools - here both the server and the .Client project builder.Services.AddBitBevToolsServices(o => o.Extensions.Add(new DemoBevToolsExtension()));
HideComponentsInNamespace("MyLibrary.Internal")keeps a library's internal components out of the tree; the internals toggle in the Components tab still shows them.- On members:
[BevToolsSensitive]redacts a value,[BevToolsIgnore]leaves a member - or, on a class, a whole component - out of BevTools. The dashboard'sUserSessionuses both. - From code:
session.PauseCapture()/ResumeCapture(),session.UseAmbient()to attribute background work to a session, andBevSessionExporter/BevTraceExporterfor the files About exports.