Skip to content

feat(dashboard): Atomizer.Dashboard package#23

Draft
mnbuhl wants to merge 9 commits intomainfrom
feature/dashboard-v4
Draft

feat(dashboard): Atomizer.Dashboard package#23
mnbuhl wants to merge 9 commits intomainfrom
feature/dashboard-v4

Conversation

@mnbuhl
Copy link
Copy Markdown
Owner

@mnbuhl mnbuhl commented May 10, 2026

Overview

Implements the first half of the Atomizer.Dashboard NuGet package — a read-only monitoring dashboard for Atomizer background jobs, schedules, queues, and servers. The dashboard ships as a React+TypeScript SPA embedded as DLL resources, served via ASP.NET Core at a configurable route prefix.

This PR covers Steps 1–6 of the 12-step plan. Steps 7–13 (ASP.NET Core integration, REST API, React views, tests, NuGet packaging) will follow on this branch.

Architecture decisions

  • IAtomizerStorage is unchanged — no new methods, no breaking changes for custom storage implementers.
  • Separate IAtomizerDashboardStorage interface lives in Atomizer.Dashboard. Two built-in adapters (InMemoryDashboardStorage, EntityFrameworkCoreDashboardStorage) wire up automatically via AddAtomizerDashboard().
  • Polling via React Query — no SignalR, no backplane requirement. Queue stats refresh every 5 s; jobs list every 30 s (both configurable). Fully multi-instance safe.
  • Single-package deploydotnet pack produces a complete artifact with the embedded SPA. Consumers never run npm.

What's in this PR

Step Description Commits
1 Dashboard project skeleton (Atomizer.Dashboard.csproj, folder structure) 4c924e2
2 Core abstractions: JobQuery, PagedResult<T> in Atomizer (+ IAtomizerEventSink — later removed as unused) 5cd0d93
3 IAtomizerDashboardStorage + InMemoryDashboardStorage with unit tests 93899f5
4 EntityFrameworkCoreDashboardStorage (LINQ-only, no raw SQL) + integration tests + CreatedAt index 12c7ca8
5 NotifyingStorageDecoratoreliminated; SignalR removed in favour of polling (no backplane required) 158b127, 9fcba1a
6 React+TypeScript+Vite+Tailwind SPA scaffold; MSBuild BuildSpa target embeds dist assets 633263d, 3cd5533

Notable implementation details

  • BuildSpa fires at BeforeTargets="DispatchToInnerBuilds" with TargetFramework == '' guard — this prevents the multi-TFM project from running npm ci three times in parallel and corrupting node_modules/esbuild.
  • SkipSpaBuild=true MSBuild property lets CI lanes without Node skip the npm step.
  • "type": "module" in package.json is required for @tailwindcss/vite (ESM-only package).
  • Node 24 LTS pinned via .nvmrc.
  • frontend/node_modules/ and frontend/dist/ excluded from git.

Steps remaining (7–13)

  • Step 7 — ASP.NET Core integration (DashboardOptions, DI, routing, EmbeddedSpaFileProvider)
  • Step 8 — REST API endpoints (/api/jobs, /api/schedules, /api/queues/stats, /api/servers)
  • Step 9 — React shell: routing, API client, React Query hooks, polling
  • Step 10 — React views: Jobs list, Job detail, Schedules, Queue stats, Servers
  • Step 11 — Comprehensive test suite (WebApplicationFactory integration tests)
  • Step 12 — NuGet packaging validation + consumer smoke test
  • Step 13 — Samples integration

Test plan

  • dotnet build triggers BuildSpa via MSBuild and embeds dist assets
  • dotnet build -p:SkipSpaBuild=true succeeds without npm
  • npm ci && npm run build produces frontend/dist/index.html
  • All existing tests pass (dotnet test)
  • dotnet csharpier check . passes
  • Steps 7–13 verification gates (tracked per step)

🤖 Generated with Claude Code

mnbuhl and others added 9 commits May 10, 2026 17:31
Replaces netstandard2.0 stub with net6.0;net8.0;net10.0 targets,
wires up ASP.NET Core FrameworkReference and Atomizer project reference,
and adds folder skeleton (Abstractions, Authorization, Configuration,
Contracts, DependencyInjection, Endpoints, Hubs, StaticFiles, Storage).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tions

Adds a null-object event sink registered via TryAddSingleton so dashboard
consumers can override it, plus JobQuery and PagedResult<T> for paginated
job querying. Includes netstandard2.0 IsExternalInit polyfill for init
property support.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…torage

Defines the IAtomizerDashboardStorage interface and QueueStats type in
the dashboard package, implements them via InMemoryDashboardStorage
reading from internal InMemoryStorage snapshots, and adds 12 unit tests
covering all query filters, pagination, ordering, and queue stats.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop the unused IAtomizerClock field from InMemoryDashboardStorage
(snapshot methods require no clock), move lease token creation into
the branches that need it, and rename the misleading active-server
test method to accurately reflect its assertion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t index

Implements IAtomizerDashboardStorage for the EF Core backend using
IDbContextFactory, AsNoTracking, and LINQ-only queries. Adds a
CreatedAt index to AtomizerJobEntityConfiguration to support efficient
ORDER BY CreatedAt DESC. Includes integration tests against PostgreSQL,
MySQL, and SQL Server containers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bootstraps the SPA in frontend/, wires it into the MSBuild pipeline via
a BuildSpa target that runs once at the outer build level (TargetFramework == '')
to avoid parallel node_modules corruption across multi-TFM builds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mnbuhl mnbuhl changed the title feat(dashboard): Atomizer.Dashboard package — steps 1–6 of 12 feat(dashboard): Atomizer.Dashboard package May 10, 2026
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