You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-**Menu JS interop crash (Bug 1):**`Menu.js``Sys.WebForms.Menu` constructor crashes when `getElement()` returns null (e.g., headless Chrome timing). Fixed by adding null guard after `getElement()` (early return if element missing) and wrapping entire constructor body in try/catch to prevent unhandled exceptions from killing the Blazor circuit. File: `src/BlazorWebFormsComponents/wwwroot/Menu/Menu.js`.
55
-
-**Calendar attribute rendering (Bug 2):**`Calendar.razor` line 64 used raw Razor expression injection to conditionally add `scope="col"` to `<th>` tags. This caused `@(UseAccessibleHeader` to appear literally in server logs due to Razor parsing issues. Fixed by replacing with proper conditional attribute: `scope="@(UseAccessibleHeader ? "col" : null)"` -- Blazor omits the attribute entirely when value is null. File: `src/BlazorWebFormsComponents/Calendar.razor`.
56
-
-**Menu auto-ID generation (Bug 3):** Menu JS interop requires a DOM element ID, but when no `ID` parameter is provided, it passes an empty string causing null element lookup. Fixed by adding `OnParametersSet` override in `Menu.razor.cs` that auto-generates `menu_{GetHashCode():x}` when ID is null/empty. File: `src/BlazorWebFormsComponents/Menu.razor.cs`.
57
-
- **Shared PagerSettings sub-component:** Created `PagerSettings` class (plain C# POCO, not a Blazor component) with all 12 Web Forms PagerSettings properties (Mode, PageButtonCount, First/Last/Next/PreviousPageText, image URLs, Position, Visible). Created `PagerPosition` enum in `Enums/` (PagerButtons already existed). Created `IPagerSettingsContainer` interface in `Interfaces/`. Created `UiPagerSettings` abstract base component following the `UiTableItemStyle` CascadingParameter pattern but for settings instead of styles. Created 3 concrete sub-component pairs: `GridViewPagerSettings`, `FormViewPagerSettings`, `DetailsViewPagerSettings` — each inherits `UiPagerSettings` and uses `[CascadingParameter(Name = "ParentXxx")]` to set properties on the parent's `PagerSettings` instance. Wired into GridView, FormView, DetailsView: added `IPagerSettingsContainer` to each control's interface list, added `PagerSettings` property + `PagerSettingsContent` RenderFragment parameter, rendered `@PagerSettingsContent` inside existing `<CascadingValue>` block. Key files: `Enums/PagerPosition.cs`, `PagerSettings.cs`, `Interfaces/IPagerSettingsContainer.cs`, `UiPagerSettings.cs`, `GridViewPagerSettings.razor(.cs)`, `FormViewPagerSettings.razor(.cs)`, `DetailsViewPagerSettings.razor(.cs)`.
Fixed three deployment pipeline issues on `fix/deployment-workflows` branch:
81
-
82
-
-**Docker version computation:**`.dockerignore` excludes `.git`, so nbgv can't run inside the Docker build. Solution: compute version with `nbgv get-version` in the workflow BEFORE Docker build, pass as `ARG VERSION` into the Dockerfile, use `-p:Version=$VERSION -p:InformationalVersion=$VERSION` in both `dotnet build` and `dotnet publish`. This pattern (compute outside, inject via build-arg) is the standard approach when `.git` isn't available inside the build context.
83
-
-**Azure App Service webhook:** Added a `curl -sf -X POST` step gated on `AZURE_WEBAPP_WEBHOOK_URL` secret. Uses `|| echo "::warning::..."` fallback so the workflow doesn't fail if the webhook is unavailable. The webhook URL comes from Azure Portal → App Service → Deployment Center.
84
-
-**nuget.org publishing:** Added a second push step after the existing GitHub Packages push, gated on `NUGET_API_KEY` secret. Both pushes use `--skip-duplicate` for idempotency.
- Secret-gated workflow steps use `if: ${{ secrets.SECRET_NAME != '' }}` for graceful fallback when secrets aren't configured
93
-
- Docker images are tagged with version number (from nbgv), `latest`, and commit SHA
94
-
- Version is computed once via nbgv and shared via GitHub Actions step outputs (`steps.nbgv.outputs.version`)
82
+
Fixed 3 pipeline issues: Docker version computation (nbgv outside build, inject via ARG), Azure App Service webhook (secret-gated curl), nuget.org dual publishing (secret-gated, --skip-duplicate). Key pattern: secret-gated steps with graceful fallback, Docker tags = version + latest + SHA, version via nbgv step outputs. Files: `.github/workflows/deploy-server-side.yml`, `.github/workflows/nuget.yml`, `samples/AfterBlazorServerSide/Dockerfile`.
95
83
96
84
Team update (2026-02-25): Deployment pipeline patterns established compute Docker version with nbgv before build, gate on secrets, dual NuGet publishing decided by Forge
97
85
@@ -107,52 +95,21 @@ Planned M9: "Migration Fidelity & Hardening" — 12 work items, ~30 gap closures
107
95
Team update (2026-02-25): Nav audit found 4 missing components + 15 missing SubPages decided by Jubilee
108
96
Team update (2026-02-25): Test audit found 5 missing smoke tests decided by Colossus
Planned M12: "Migration Analysis Tool (PoC)" — 13 work items. A CLI tool (`bwfc-migrate`) that analyzes existing Web Forms applications and produces migration reports showing control coverage, gaps, code-behind pattern detection, and complexity scoring.
**Key insight:** At 51/53 components, the highest-value work is no longer building components — it's reducing the friction of using the ones we have. A migration analysis tool turns a week of manual evaluation into a 5-second CLI invocation.
📌 Team update (2026-02-25): Milestone 12 planned — 13 WIs, "Migration Analysis Tool PoC". CLI tool for Web Forms app analysis with control mapping, gap identification, complexity scoring, and report generation. — decided by Forge
126
105
127
106
Team update (2026-02-25): Consolidated audit reports now use `planning-docs/AUDIT-REPORT-M{N}.md` pattern for all milestone audits decided by Beast
128
107
129
108
### Summary: Skins & Themes Research and PoC Architecture (2026-02-25)
130
109
131
-
Deep-dived ASP.NET Web Forms Skins & Themes system (.NET 4.8) and produced two planning documents:
132
-
133
-
**Key findings:**
134
-
- Web Forms themes use `.skin` files in `App_Themes/{ThemeName}/` folders with control property declarations
135
-
- Default skins (no SkinID) apply automatically; named skins (SkinID="x") are opt-in
136
-
-`Theme` property overrides page declarations; `StyleSheetTheme` acts as defaults that pages can override
137
-
- Skins apply during `PreInit` phase — maps to Blazor `OnInitialized`
138
-
- Only appearance properties are themeable (not behavioral properties like DataSource)
139
-
140
-
**Existing infrastructure:**
141
-
-`SkinID` (string) and `EnableTheming` (bool) already exist on `BaseWebFormsComponent` but are marked `[Obsolete]`
- CascadingParameter pattern already used for parent-child style composition in login controls
145
-
- Zero runtime theming infrastructure exists today
146
-
147
-
**Architecture decision:** Recommended CascadingValue ThemeProvider with C# configuration (Option A). Evaluated 4 options: (A) C# config, (B) .skin file parser, (C) CSS isolation, (D) JSON config. Option C rejected (can't set non-CSS properties). Option A chosen for type safety, IDE support, testability, and no build tooling requirement. Options B and D can layer on top in M11.
148
-
149
-
**Suitability rating:** Medium — good foundations exist (SkinID, EnableTheming, styling infrastructure) but architectural gap (no ThemeProvider, no theme-reading logic in base classes).
Researched ASP.NET Web Forms Skins & Themes (.NET 4.8). Key findings: `.skin` files in `App_Themes/`, default vs named skins (SkinID), Theme (override) vs StyleSheetTheme (defaults), skins apply at PreInit → maps to OnInitialized. Existing infrastructure: SkinID (string) + EnableTheming (bool) on BaseWebFormsComponent (marked [Obsolete]), mature styling pipeline (IStyle/WebColor/FontInfo/TableItemStyle), CascadingParameter pattern in login controls. Suitability: Medium.
152
111
153
-
**Deliverables:**
154
-
-`planning-docs/SKINS-THEMES-COMPATIBILITY-REPORT.md` — full research and compatibility analysis
155
-
-`planning-docs/SKINS-THEMES-POC-PLAN.md` — M10 PoC architecture plan with 5 work items
112
+
Architecture: CascadingValue ThemeProvider with C# config (Option A). Rejected CSS-only (can't set non-CSS properties). Options B (.skin parser) and D (JSON) can layer on in M11. Issues #364-#368 (M10 PoC) + #369 (M11). Deliverables: `planning-docs/SKINS-THEMES-COMPATIBILITY-REPORT.md` and `planning-docs/SKINS-THEMES-POC-PLAN.md`.
156
113
157
114
📌 Team update (2026-02-25): Skins & Themes PoC architecture decided — CascadingValue ThemeProvider with C# configuration. 5 work items on M10 (#364-#368), M11 planning issue #369. — decided by Forge
📌 Test pattern: GridView style sub-components use named RenderFragments (`<RowStyleContent>`, etc.) containing `<GridViewRowStyle BackColor="color" />`. The sub-component configures the GridView's TableItemStyle via CascadingParameter "ParentGridView". Styles render as inline `style` attributes on `<tr>` elements. — Rogue
52
-
53
-
📌 Test pattern: GridView AlternatingRowStyle is always initialized (non-null `new TableItemStyle()`), so `GetRowStyle()` returns it for odd rows even when not configured. RowStyle only applies to even-indexed rows; to style ALL rows, set both RowStyle and AlternatingRowStyle. — Rogue
54
-
55
-
📌 Test pattern: GridView with `AutoGenerateColumns="false"` renders in two passes: first pass initializes style sub-components (empty table), second pass renders table after BoundField children register via `AddColumn`. bUnit waits for both renders. — Rogue
Wrote 41 bUnit tests across 6 new test files for P2 features:
60
-
61
-
**CrudEvents.razor (ListView, 12 tests):** HandleCommand routes Edit→sets EditIndex+fires ItemEditing, Cancel→clears EditIndex+fires ItemCanceling, Delete→fires ItemDeleting+ItemDeleted, Insert→fires ItemInserting+ItemInserted, Update→fires ItemUpdating+ItemUpdated. Unknown command→fires ItemCommand. EditIndex=-1 shows ItemTemplate for all. EmptyItemTemplate renders when Items empty. InsertItemTemplate at FirstItem/LastItem positions. ItemEditing cancellation prevents EditIndex change. EditItemTemplate rendering verified via HandleCommand (EditIndex set confirmed; template re-evaluation is a known component gap).
62
-
63
-
**StyleSubComponents.razor (DataGrid, 11 tests):** DataGridItemStyle on data rows, AlternatingItemStyle on odd rows, HeaderStyle on thead, FooterStyle on tfoot, PagerStyle on pager row, SelectedItemStyle at SelectedIndex, EditItemStyle at EditItemIndex. Caption+CaptionAlign render correctly. GridLines→rules attribute. UseAccessibleHeader→th scope=col. CellPadding+CellSpacing on table.
64
-
65
-
**Events.razor (DataGrid, 3 tests):** PageIndexChanged fires when pager link clicked, SortCommand fires on sortable header click, SelectedIndex default is -1.
66
-
67
-
**LevelStyles.razor (Menu, 7 tests):** LevelMenuItemStyles applies per-depth CssClass, Level 1 items get index 0 style, Level 2 items get index 1 style, LevelSelectedStyles applies after click, LevelSubMenuStyles applies background-color to submenu ul, Level styles override static/dynamic styles.
68
-
69
-
**BackImageUrl.razor (Panel, 3 tests):** BackImageUrl renders as background-image in style, not set→no background-image, URL-encoded characters preserved.
70
-
71
-
**LoginOrientation.razor (Login, 5 tests):** Default Orientation is Vertical (fields in separate rows), Horizontal puts all fields in one row with 4 tds, TextOnLeft labels align right, TextOnTop labels above inputs with colspan, Horizontal+TextOnTop puts both labels in same row.
72
-
73
-
📌 Test pattern: ListView HandleCommand must be called via `cut.InvokeAsync()` because it calls StateHasChanged() which requires the Blazor Dispatcher context. Direct `await theListView.HandleCommand()` throws InvalidOperationException. — Rogue
74
-
75
-
📌 Test pattern: DataGrid style sub-components use named RenderFragments (`<ItemStyleContent>`, `<HeaderStyleContent>`, etc.) containing `<DataGridItemStyle BackColor="color" />`. WebColor values must be declared as variables (`WebColor red = "Red";`) then passed as `BackColor="red"` — not string literals. — Rogue
76
-
77
-
📌 Test pattern: Menu tests that use `FindAll("a")` must use `FindAll("li a")` to exclude the accessibility skip-link `<a>` rendered before the menu. JSInterop.Mode = JSRuntimeMode.Loose required for all Menu tests. — Rogue
78
-
79
-
📌 Test pattern: Login control tests require AuthenticationStateProvider + NavigationManager mock services. Use `Orientation ori = Orientation.Horizontal;` variable pattern to avoid Razor enum name collision. Login renders 4 layout combos based on Orientation × TextLayout (Vertical/Horizontal × TextOnLeft/TextOnTop). — Rogue
80
-
81
-
📌 Test pattern: Menu Orientation tests require JSInterop.Mode = JSRuntimeMode.Loose and @using BlazorWebFormsComponents.Enums. Login control tests require AuthenticationStateProvider and NavigationManager mock services. — Rogue
51
+
📌 Key test patterns (consolidated): GridView styles use named RenderFragments + CascadingParameter "ParentGridView". AlternatingRowStyle always initialized. AutoGenerateColumns=false → two-pass rendering. ListView HandleCommand requires `cut.InvokeAsync()`. DataGrid WebColor values must be variables. Menu tests use `FindAll("li a")` to exclude skip-link. Login tests need AuthenticationStateProvider + NavigationManager mocks + `Orientation ori = Orientation.Horizontal` variable pattern. JSInterop.Mode = JSRuntimeMode.Loose for Menu/Login. — Rogue
82
52
83
53
Team update (2026-02-24): M8 scope excludes version bump to 1.0 and release decided by Jeffrey T. Fritz
84
54
Team update (2026-02-24): PagerSettings shared sub-component created may need bUnit tests decided by Cyclops
0 commit comments