Skip to content

Comments

Milestone 4 & 5: Chart Component + 53-Control Feature Audit#341

Merged
csharpfritz merged 38 commits intoFritzAndFriends:devfrom
csharpfritz:milestone4/chart-component
Feb 23, 2026
Merged

Milestone 4 & 5: Chart Component + 53-Control Feature Audit#341
csharpfritz merged 38 commits intoFritzAndFriends:devfrom
csharpfritz:milestone4/chart-component

Conversation

@csharpfritz
Copy link
Collaborator

@csharpfritz csharpfritz commented Feb 23, 2026

Milestone 4: Chart Component + Milestone 5: Feature Comparison Audit

Chart Component (Milestone 4)

New Component

  • Chart component using Chart.js via JS interop (canvas rendering)
  • Supports 9 chart types: Bar, Column, Line, Area, Pie, Doughnut, Scatter, Bubble, Radar
  • ChartConfigBuilder - pure static class for testable config generation
  • ChartJsInterop - lazy ES module interop pattern
  • Proper per-segment color arrays for Pie/Doughnut charts

Chart Samples and Documentation

  • Sample pages for all 9 chart types with interactive demos
  • Chart.js ES module bundled at wwwroot/js/chart-interop.js
  • Documentation at docs/DataControls/Chart.md with screenshots

UI Overhaul (Sample App)

  • Phase 1-3 Bootstrap 5 redesign of AfterBlazorServerSide sample app
  • Dynamic ComponentCatalog-driven sidebar navigation
  • Responsive layout with branding

53-Control Feature Comparison Audit (Milestone 5)

Audit Documents

  • Individual audit documents for all 53 ASP.NET Web Forms controls in planning-docs/
  • Each document covers: properties, events, methods, HTML output comparison
  • Features categorized as: Match, Needs Work, Missing, N/A

Summary Statistics (from planning-docs/SUMMARY.md)

  • Overall Feature Health: 66.3% across all controls
  • Editor Controls: 68.1% (27 controls)
  • Data Controls: 51.5% (9 controls)
  • Validation Controls: 71.2% (7 controls)
  • Navigation Controls: 78.7% (3 controls)
  • Login Controls: 64.3% (7 controls)

Key Findings

  • P0 gaps: BaseWebFormsComponent missing AccessKey/ToolTip; DataBoundComponent lacks style inheritance
  • P1 gaps: Validator Display/SetFocusOnError; Calendar style properties
  • Chart is the first component requiring JavaScript interop

Themes and Skins Strategy

  • New document docs/Migration/ThemesAndSkins.md proposing CSS-based alternatives

Deferred Controls Update

  • Updated docs/Migration/DeferredControls.md - Chart moved to Partially Implemented

Test Results

  • 949 bUnit tests - all passing
  • 162 Playwright integration tests - all passing

Breaking Changes

None.

Next Steps (Milestone 6)

Use audit documents as work backlog to implement missing/broken features.

Copilot AI and others added 30 commits February 9, 2026 17:08
Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>
Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>
Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>
Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>
…ends#333)

- Create CalendarSelectionMode enum (None, Day, DayWeek, DayWeekMonth)
- Refactor Calendar.SelectionMode from string to CalendarSelectionMode enum
- Remove .GetAwaiter().GetResult() blocking call in CreateDayRenderArgs
- Add Caption, CaptionAlign, UseAccessibleHeader properties
- Update tests and samples to use enum values
- Calendar: date selection, selection modes, styling, day/title formats, events

- FileUpload: basic upload, file type filtering, multiple files, disabled, styled

- ImageMap: navigate/postback/mixed hot spot modes, rectangle/circle/polygon shapes

- Updated NavMenu and ComponentList with links to all three new components
…ents into dev

# Conflicts:
#	docs/EditorControls/FileUpload.md
…Friends#338 merge

The FileUpload PR (FritzAndFriends#338) inadvertently reverted Sprint 1 gate review
entries from agent histories (beast, cyclops, forge, jubilee, rogue)
and downgraded the FileUpload InputFile decision in decisions.md.

Restored from commit f85aa42 (docs(ai-team): Sprint 1 gate review results).
Creates .agent.md files for all 6 team agents (Beast, Cyclops, Forge,
Jubilee, Rogue, Scribe) so they appear in GitHub Copilot's agent picker.
Content sourced from existing .ai-team/agents/*/charter.md files.
Squad is the single Copilot agent that delegates to the specialized
agents defined in .ai-team/agents/. Individual agent files were
incorrectly created  the correct pattern is one coordinator agent
(squad.agent.md) that routes work to Forge, Cyclops, Beast, Jubilee,
Rogue, and Scribe based on task type.
Session: 2026-02-10-sprint2-complete
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 2 session (4 components shipped with docs, samples, tests)
- Merged Sprint 2 design review decision from inbox
- Removed duplicate FileUpload InputFile decision from inbox (already consolidated)
- Appended Sprint 2 completion decision to decisions.md
- Propagated cross-agent updates to all 5 agent histories
…ents into dev

# Conflicts:
#	docs/UtilityFeatures/PageService.md
#	samples/AfterBlazorServerSide/Components/Pages/ControlSamples/Calendar/Index.razor
Session: 2026-02-11-sprint3-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-11-sprint3-planning.md
- Merged 3 decisions from inbox into decisions.md
- Updated status.md to reflect 48/53 components complete
- Sprint 3 scope: DetailsView + PasswordRecovery
- Propagated cross-agent updates to all agent history files
Session: 2026-02-12-sprint3-execution
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 3 execution session
- Merged 7 decisions from inbox into decisions.md
- Sprint 3 gate review: DetailsView + PasswordRecovery APPROVED
- Propagated cross-agent updates to Beast, Colossus, Cyclops, Rogue, Jubilee
- status.md updated to 50/53 (94%)
Session: 2026-02-12-milestone4-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-12-milestone4-planning.md
- Merged decisions from inbox (Chart.js evaluation, milestone plan, milestones directive)
- Propagated milestone 4 updates to 5 agent history files
Session: 2026-02-12-milestone4-planning
Requested by: Scribe (automatic)

Changes:
- Summarized Forge history.md (exceeded ~12KB threshold)
- Preserved all team updates and key patterns
- Add Chart, ChartSeries, ChartArea, ChartLegend, ChartTitle components
- Add JS interop infrastructure (chart-interop.js, ChartJsInterop.cs)
- Add ChartConfigBuilder for component state -> Chart.js JSON config
- Add SeriesChartType, ChartPalette, Docking, ChartDashStyle enums
- Add DataPoint and Axis POCOs
- Add 140 bUnit tests for Chart components (866 total, all passing)
- Add 8 Chart sample pages (Column, Line, Bar, Pie, Area, Doughnut, Scatter, StackedColumn)
- Add 19 Chart integration tests
- Add Chart documentation and update mkdocs.yml, README, status.md
- Fix integration test console error filter for ASP.NET structured logs
- Fix integration test filter for external resource loading errors
- Fix duplicate FileUpload route (delete old Pages/ControlSamples/FileUpload/Default.razor)
- Fix ChangePassword and CreateUserWizard test assertions for EditForm rendering
- All tests green: 866 bUnit + 124 integration tests
Session: 2026-02-14-chart-implementation
Requested by: Jeffrey T. Fritz

Changes:
- Logged session: Chart data binding and Playwright tests shipped
- Merged 7 decision files from inbox (Chart visual tests, data binding, implementation, samples)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix ChartSeries.ToConfig() to support Items/XValueMember/YValueMembers data binding
- Add 12 data binding unit tests (152 Chart tests total)
- Create 4 new sample pages: DataBinding, MultiSeries, Styling, ChartAreas
- Add 38 Playwright integration tests for Chart appearance verification
- All 143 integration tests and 152 Chart unit tests pass

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ChartAreas, DataBinding, MultiSeries, Styling routes now tested
- All 42 Chart integration tests pass
- Completes Forge's gate review requirements

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…randing

- Upgraded Bootstrap 4.3.1 to 5.3.3
- Fixed pl-4 -> ps-4 utility class in NavMenu.razor
- Created ComponentCatalog.cs with 36 components across 6 categories
- Added GetByCategory, GetByRoute, Search helper methods
- Created logo.svg with migration concept (Web Forms -> Blazor)
- Added brand-colors.css with custom properties
- Updated App.razor with favicon and brand stylesheet

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Redesigned MainLayout.razor with modern Bootstrap 5 navbar
  - Fixed-top navbar with logo, search placeholder, external links
  - Collapsible sidebar with hamburger menu on mobile
  - Footer with GitHub link and MIT License
  - data-bs-theme attribute for future dark mode support
- Refactored NavMenu.razor to use ComponentCatalog
  - Data-driven rendering with collapsible category sections
  - Tooltips on component links with descriptions
  - Current page highlighting and auto-expand categories
  - Badge showing component count per category
- Created SamplePageTemplate.razor with card-based layout
  - Title, Description, DemoContent, CodeExample sections
  - Consistent styling using brand colors
- Fixed Menu_Renders_WithItems test (ul/li vs table)

All 147 integration tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Implemented client-side search with Fuse.js fuzzy matching
  - SearchBox.razor with debounced search (200ms)
  - Keyboard navigation (up/down/enter/escape)
  - Match highlighting in results
  - Category badges and truncated descriptions
- Redesigned homepage with hero section and card-based catalog
  - Gradient hero with CTA buttons (Get Started, View on GitHub)
  - 6 category cards with component counts and links
  - Responsive grid (3/2/1 columns for desktop/tablet/mobile)
- Fixed sidebar layout issues
  - Removed redundant header text
  - Categories expanded by default on desktop
  - Mobile nav collapse on link click

All 147 integration tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Added 4 screenshots showcasing the sample site:
- Homepage with component catalog
- GridView with interactive data binding
- Chart component with Chart.js
- Fuzzy search feature

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixed route mismatches between ComponentCatalog and actual page routes:
- MasterPage: /ControlSamples/MasterPage -> /control-samples/masterpage
- FormView: /ControlSamples/FormView -> /ControlSamples/FormView/Simple
- DataList: SimpleFlow subpage -> Flow (matches actual route)
- Validation controls: Removed /Validations/ prefix from routes
- Login controls: Removed /LoginControls/ prefix from routes
- LoginStatus: Removed NotAuthenticated subpage (has separate route)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The global footer in App.razor was spanning full width and appearing
behind the fixed-position sidebar. Added inline styles in head to
ensure the footer respects sidebar width with responsive handling.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
csharpfritz and others added 7 commits February 23, 2026 09:25
…eenshots

- Fix per-segment color assignment for pie/doughnut charts in ChartConfigBuilder
- Replace chart.min.js placeholder with real Chart.js v4.4.8 (201KB)
- Add Playwright-generated screenshots for all 8 chart types to docs/images/chart/
- Add Chart Type Gallery section to Chart.md documentation
- Remove palette limitation warnings (bug is now fixed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evaluate 5 Blazor-native approaches to replicate Web Forms Themes and
Skins functionality: CSS Custom Properties, CascadingValue ThemeProvider,
Generated CSS Isolation, DI-based Configuration, and Hybrid.

Recommend CascadingValue ThemeProvider as the primary approach due to
full Web Forms fidelity (Theme/StyleSheetTheme semantics, SkinID support,
all property types). Document is exploratory per Jeff's request.

- Create docs/Migration/ThemesAndSkins.md with full analysis
- Add to mkdocs.yml nav under Migration section
- Record decision in .ai-team/decisions/inbox/
- Update forge history with learnings

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Session: 2026-02-23-feature-audit
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-23-feature-audit.md
- Merged 8 decisions from inbox into decisions.md
- Consolidated overlapping decisions (AccessKey/ToolTip, Chart architecture, DataBoundComponent gap)
- Propagated updates to 6 agent history files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…trategy

- Created 53 audit documents in planning-docs/ comparing every ASP.NET Web Forms
  control against its Blazor component implementation
- Created planning-docs/SUMMARY.md with aggregate gap analysis (66.3% feature match)
- Created docs/Migration/ThemesAndSkins.md with 5 evaluated migration approaches
  (recommended: CascadingValue ThemeProvider pattern)
- Updated mkdocs.yml nav with ThemesAndSkins entry
- Key findings: AccessKey/ToolTip universally missing, GridView weakest at 20.7%,
  DetailsView+PasswordRecovery stranded on unmerged sprint3 branch,
  7 base-class fixes would close ~180 gaps across the library

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Brings in sprint3/detailsview-passwordrecovery (FritzAndFriends#340):
- DetailsView component with paging, edit mode, command rows
- PasswordRecovery component with 3-step flow
- DataBinder/ViewState utility samples
- Local SVG placeholder images replacing external URLs
- bUnit and Playwright integration tests

Conflict resolution:
- DeferredControls.md: Kept Chart as Partially Implemented (HEAD)
  with dev's richer Substitution/Xml documentation
- ControlSampleTests.cs: Combined Chart tests (HEAD) + Utility
  tests (dev), kept comprehensive error filtering
- InteractiveComponentTests.cs: Took dev's thorough field-level
  assertions + all new DetailsView/PasswordRecovery tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Integrates remote work: Phase 1-3 UI overhaul (Bootstrap 5,
ComponentCatalog, sidebar), chart data binding samples, and
Playwright integration tests for new sample pages.

Conflict: NavMenu.razor  took remote's ComponentCatalog-driven
dynamic nav (UI overhaul) over local's static TreeNode list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment on lines +1328 to +1335
if (yValue != null)
{
point.YValues = new[] { Convert.ToDouble(yValue) };
}
else
{
point.YValues = Array.Empty<double>();
}

Check notice

Code scanning / CodeQL

Missed ternary opportunity

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
Comment on lines +101 to +114
foreach (var s in seriesList)
{
if (s.Points != null && s.Points.Count > 0)
{
foreach (var p in s.Points)
{
if (!string.IsNullOrEmpty(p.Label))
labels.Add(p.Label);
else if (p.XValue != null)
labels.Add(p.XValue);
}
break;
}
}

Check notice

Code scanning / CodeQL

Missed opportunity to use Where

This foreach loop [implicitly filters its target sequence](1) - consider filtering the sequence explicitly using '.Where(...)'.
Comment on lines +135 to +148
if (s.ChartType == SeriesChartType.Point)
{
dataset["data"] = s.Points.Select(p => new Dictionary<string, object>
{
["x"] = p.XValue ?? 0,
["y"] = p.YValues?.Length > 0 ? p.YValues[0] : 0
}).ToList();
}
else
{
dataset["data"] = s.Points
.Select(p => p.YValues?.Length > 0 ? p.YValues[0] : 0.0)
.ToList();
}

Check notice

Code scanning / CodeQL

Missed ternary opportunity

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
if (area.AxisX != null)
{
var xAxis = BuildAxisConfig(area.AxisX);
if (scales.ContainsKey("x"))

Check notice

Code scanning / CodeQL

Inefficient use of ContainsKey

Inefficient use of 'ContainsKey' and [indexer](1).
if (area.AxisY != null)
{
var yAxis = BuildAxisConfig(area.AxisY);
if (scales.ContainsKey("y"))

Check notice

Code scanning / CodeQL

Inefficient use of ContainsKey

Inefficient use of 'ContainsKey' and [indexer](1).
Comment on lines +113 to +121
if (Items != null && !string.IsNullOrEmpty(YValueMembers))
{
config.Points = ExtractDataPointsFromItems();
}
else
{
// Fall back to manually-specified Points
config.Points = Points;
}

Check notice

Code scanning / CodeQL

Missed ternary opportunity

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
Comment on lines +233 to +236
catch
{
return false;
}

Check notice

Code scanning / CodeQL

Generic catch clause

Generic catch clause.
Comment on lines +1328 to +1335
if (yValue != null)
{
point.YValues = new[] { Convert.ToDouble(yValue) };
}
else
{
point.YValues = Array.Empty<double>();
}

Check notice

Code scanning / CodeQL

Missed ternary opportunity Note test

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
Comment on lines +101 to +114
foreach (var s in seriesList)
{
if (s.Points != null && s.Points.Count > 0)
{
foreach (var p in s.Points)
{
if (!string.IsNullOrEmpty(p.Label))
labels.Add(p.Label);
else if (p.XValue != null)
labels.Add(p.XValue);
}
break;
}
}

Check notice

Code scanning / CodeQL

Missed opportunity to use Where Note

This foreach loop
implicitly filters its target sequence
- consider filtering the sequence explicitly using '.Where(...)'.
Comment on lines +135 to +148
if (s.ChartType == SeriesChartType.Point)
{
dataset["data"] = s.Points.Select(p => new Dictionary<string, object>
{
["x"] = p.XValue ?? 0,
["y"] = p.YValues?.Length > 0 ? p.YValues[0] : 0
}).ToList();
}
else
{
dataset["data"] = s.Points
.Select(p => p.YValues?.Length > 0 ? p.YValues[0] : 0.0)
.ToList();
}

Check notice

Code scanning / CodeQL

Missed ternary opportunity Note

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
if (area.AxisX != null)
{
var xAxis = BuildAxisConfig(area.AxisX);
if (scales.ContainsKey("x"))

Check notice

Code scanning / CodeQL

Inefficient use of ContainsKey Note

Inefficient use of 'ContainsKey' and
indexer
.
if (area.AxisY != null)
{
var yAxis = BuildAxisConfig(area.AxisY);
if (scales.ContainsKey("y"))

Check notice

Code scanning / CodeQL

Inefficient use of ContainsKey Note

Inefficient use of 'ContainsKey' and
indexer
.
Comment on lines +113 to +121
if (Items != null && !string.IsNullOrEmpty(YValueMembers))
{
config.Points = ExtractDataPointsFromItems();
}
else
{
// Fall back to manually-specified Points
config.Points = Points;
}

Check notice

Code scanning / CodeQL

Missed ternary opportunity Note

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
Comment on lines +233 to +236
catch
{
return false;
}

Check notice

Code scanning / CodeQL

Generic catch clause Note

Generic catch clause.
The UI overhaul added ComponentCatalog-driven NavMenu and SearchBox
components to AfterBlazorServerSide. Since AfterBlazorClientSide links
Layout files via content references, it needs:

- ComponentCatalog.cs linked as a compile item (NavMenu depends on it)
- @using AfterBlazorServerSide added to client _Imports.razor
- @using AfterBlazorServerSide.Components.Shared moved from
  MainLayout.razor to server-side _Imports.razor (avoids namespace
  resolution failure in client project where Shared components are
  not linked)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@csharpfritz csharpfritz merged commit 635bb3d into FritzAndFriends:dev Feb 23, 2026
4 checks passed
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.

2 participants