Compare commits

..

No commits in common. "92296c479bd7503465d218503e89487d7c97fcbe" and "79eceff47a614395d71741d9c05146701d0ea3f0" have entirely different histories.

39 changed files with 110 additions and 1109 deletions

View File

@ -1,43 +0,0 @@
# Topic Codes — registry for AyCode.Blazor's own topics (`ACBLAZOR`)
Per the Framework-First Design Principle, this Layer 1 registry lists **only AyCode.Blazor's own (`ACBLAZOR`) topics**. Lower-layer (inherited) topics live in their own repos' registries — at runtime, the `docs-check` skill walks `own-dep-repos` from the invocation point to gather all inherited topics. AyCode.Blazor inherits from `AyCode.Core` (see this repo's `@repo.own-dep-repos`).
Full ID format: `<PREFIX>-<TOPIC>-<TYPE>-<RAND>` — see `AyCode.Core/.github/REPO_PREFIXES.md` for the format spec.
## ACBLAZOR topic codes
| Code | Topic | Scope | Docs location |
|---------|-----------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------------------------|
| `GRID` | MGGRID (grid component) | MgGrid component family: layout, CRUD, columns, toolbar, rendering | `AyCode.Blazor.Components/docs/MGGRID/` |
## Type codes (universal — see framework registry)
Type codes (`I`, `T`, `B`, `C`, `DEC`) are universal across all repos and defined in the framework's `TOPIC_CODES.md` (`AyCode.Core/.github/skills/docs-check/references/TOPIC_CODES.md`). This file does not duplicate them.
## ID format rules
See the framework's `TOPIC_CODES.md` (`AyCode.Core/.github/skills/docs-check/references/TOPIC_CODES.md`) for the full ID format rules and Status conventions. This file only registers ACBLAZOR's own topic codes; ACCORE topics are inherited via this repo's `own-dep-repos`.
## Examples (ACBLAZOR only)
```
ACBLAZOR-GRID-T-V4P7 # AyCode.Blazor's MgGrid TODO (e.g., "Generic ID generation in MgGridBase.SetNewId")
ACBLAZOR-GRID-T-S2L9 # AyCode.Blazor's MgGrid TODO (e.g., "Implement local grouping")
ACBLAZOR-GRID-I-XXXX # placeholder for the first MgGrid issue once one is observed
```
## Adding a new ACBLAZOR topic
1. Propose the code (2-5 uppercase chars), short and mnemonic, scoped to AyCode.Blazor's UI-framework domain.
2. Check it doesn't collide with C# class-name prefixes (`Ac*` / `Mg*`).
3. Check it doesn't collide with existing ACBLAZOR topic codes in the table above.
4. Check it doesn't visually collide with framework (`ACCORE-*`) topic codes that this repo references — though the `<PREFIX>` component disambiguates, visual distinction helps readers.
5. Add a row to the table above.
6. Create the topic folder under the relevant project: `AyCode.Blazor.<Project>/docs/{TOPIC_FOLDER_NAME}/` with `README.md`, optional `{TOPIC_FOLDER_NAME}_ISSUES.md`, `{TOPIC_FOLDER_NAME}_TODO.md`.
7. Optional: add an `LLMP-DEC-N` entry in the workspace-level `LLM_PROTOCOL_DECISIONS.md` if the new topic is workspace-meta-significant.
## Cross-references
- **Framework registry** (universal type codes, ID format spec, Status conventions): `AyCode.Core/.github/skills/docs-check/references/TOPIC_CODES.md` (resolved via this repo's `own-dep-repos`).
- **Repo prefix scheme**: `AyCode.Core/.github/REPO_PREFIXES.md`.
- **Decision Log**: `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md`.

File diff suppressed because one or more lines are too long

View File

@ -15,3 +15,6 @@ Grid component integration tests for `MgGridBase` layout persistence, column ren
- Master grid detection.
- Reflection-based column building (verifies Id, ProductName, Quantity columns).
- `MgGridDataColumn.UrlLink` rendering with token replacement.
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -1,9 +1,5 @@
# AyCode.Blazor.Components.Tests
@project {
type = "test"
}
bUnit + MSTest component test project targeting net10.0. Tests Blazor component behavior including grid layout persistence and column rendering.
## Key Files
@ -19,3 +15,6 @@ bUnit + MSTest component test project targeting net10.0. Tests Blazor component
| MSTest | 4.0.2 | NuGet |
| AyCode.Blazor.Components | -- | ProjectReference |
| AyCode.Services.Server.Tests | -- | ProjectReference |
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<RunAOTCompilation>true</RunAOTCompilation>
@ -55,11 +55,6 @@
<Folder Include="Services\Logins\" />
</ItemGroup>
<ItemGroup>
<None Include="docs\**\*.md" />
<None Include="**\README.md" Exclude="$(DefaultItemExcludes);docs\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AyCode.Blazor.Models.Server\AyCode.Blazor.Models.Server.csproj" />
<ProjectReference Include="..\AyCode.Blazor.Models\AyCode.Blazor.Models.csproj" />

View File

@ -5,3 +5,6 @@ Generic card-based view component that renders items in a responsive CSS Grid la
## Key Files
- **`MgCardView.razor.cs`** -- `MgCardView<TItem>` component. Accepts `Data`, `CardTemplate`, responsive column counts (`ColumnCountXs/Sm/Lg`), optional pager (`ShowPager`, `PageSize` default 12), optional filter panel, container height, and `ScrollToItem` with JS interop for auto-scrolling. Fires `OnCardClick` when a card is tapped.
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -770,10 +770,13 @@ public abstract class MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClie
private async Task Grid_LayoutAutoLoading(GridPersistentLayoutEventArgs e)
{
BeginUpdate();
// Save the default layout before loading any saved layout
_defaultLayoutJson ??= JsonSerializer.Serialize(SaveLayout());
e.Layout = await LoadLayoutFromLocalStorageAsync(AutomaticLayoutStorageKey);
EndUpdate();
}
private async Task Grid_LayoutAutoSaving(GridPersistentLayoutEventArgs e)
@ -802,7 +805,9 @@ public abstract class MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClie
{
try
{
BeginUpdate();
var json = JsonSerializer.Serialize(layout);
EndUpdate();
await JSRuntime.InvokeVoidAsync("localStorage.setItem", localStorageKey, json);
}

View File

@ -1,15 +1,18 @@
# Grids
Core grid system built on DevExpress `DxGrid`. For the full technical reference see `AyCode.Blazor.Components/docs/MGGRID/README.md`.
Core grid system built on DevExpress `DxGrid` with SignalR-based data binding, CRUD operations, layout persistence, fullscreen mode, and an info panel for row details.
## Key Files
- **`MgGridBase.cs`** — `MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClient>`, the main abstract grid component. Extends `DxGrid` with SignalR CRUD, layout persistence, master-detail hierarchy, edit state tracking, fullscreen toggle.
- **`MgGridWithInfoPanel.razor`** — `DxSplitter` wrapper: grid (left) + InfoPanel (right), fullscreen overlay, splitter size persistence.
- **`MgGridToolbarBase.cs`** — Extends `DxToolbar` with `Grid`, `RefreshClick`, and `ShowOnlyIcon` parameters.
- **`MgGridToolbarTemplate.razor`** — Full toolbar template: New/Edit/Delete/Save/Cancel, row navigation, layout menu (Load/Save/Reset), column chooser, export, reload, fullscreen. Extensible via `ToolbarItemsExtended`.
- **`MgGridDataColumn.cs`** — Extends `DxGridDataColumn` with InfoPanel parameters (`ShowInInfoPanel`, `InfoPanelOrder`, `InfoPanelDisplayFormat`) and `UrlLink` template with `{Property}` placeholder substitution via compiled accessors.
- **`MgGridInfoPanel.razor`** / **`.razor.cs`** — `MgGridInfoPanel` implementing `IInfoPanelBase`. Responsive column layout (1-4 columns with breakpoints), edit/view mode with typed editors, template system, sticky positioning via JS interop.
- **`MgGridSignalRDataSource.cs`** — `GridCustomDataSource` wrapping `AcSignalRDataSource`. Local cache for seen filter criteria, background refresh.
- **`GridEditMode.cs`** — `MgGridEditState` enum: `None`, `New`, `Edit`.
- **`MgGridHelper.cs`**, **`MgGridToolbarHelper.cs`**, **`MgGridInfoPanelHelper.cs`** — Placeholder helpers (empty).
- **`MgGridBase.cs`** -- `MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClient>`, the main abstract grid component. Extends `DxGrid` and binds to an `AcSignalRDataSource` for real-time CRUD via SignalR message tags. Supports master-detail hierarchy (`ParentGrid`, `GetRootGrid`), row navigation, edit state tracking, layout auto-save/load/reset via localStorage, and fullscreen toggle.
- **`MgGridSignalRDataSource.cs`** -- `MgGridSignalRDataSource<TDataItem, TId>`, a `GridCustomDataSource` that wraps `AcSignalRDataSource`. Returns local data instantly for previously-seen filter criteria while refreshing from the server in the background. Handles filter, sort, paging, unique values, and summary calculations locally.
- **`MgGridDataColumn.cs`** -- Extends `DxGridDataColumn` with InfoPanel visibility/order parameters and a `UrlLink` template that renders cells as hyperlinks with `{Property}` placeholder substitution via compiled accessors.
- **`MgGridInfoPanel.razor.cs`** -- `MgGridInfoPanel` component implementing `IInfoPanelBase`. Displays focused-row details with responsive column layout, edit/view mode, sticky positioning via JS interop, and cached column/display-text lookups.
- **`MgGridToolbarBase.cs`** -- Extends `DxToolbar` with `Grid`, `RefreshClick`, and `ShowOnlyIcon` parameters.
- **`GridEditMode.cs`** -- `MgGridEditState` enum: `None`, `New`, `Edit`.
- **`MgGridHelper.cs`** -- Placeholder helper (empty).
- **`MgGridToolbarHelper.cs`** -- Placeholder helper (empty).
- **`MgGridInfoPanelHelper.cs`** -- Placeholder helper (empty).
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -19,3 +19,6 @@ DevExpress component wrappers and grid infrastructure for the AyCode Blazor comp
- **`CardViews/`** -- Generic card-based view component with pagination.
- **`Grids/`** -- Core grid system with SignalR data binding, toolbar, info panel, and layout persistence.
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -1,29 +1,7 @@
# AyCode.Blazor.Components
@project {
type = "framework"
own-dep-projects = [
"AyCode.Core, AyCode.Entities, AyCode.Interfaces, AyCode.Models, AyCode.Services, AyCode.Services.Server, AyCode.Utils (in AyCode.Core repo)"
]
}
Blazor Razor component library targeting .NET 10. Provides reusable DevExpress-based UI components, a SignalR-powered grid system, and LINQ expression serialization services.
## Documentation
| Document | Topic |
|---|---|
| `MGGRID/README.md` | MgGrid system — overview, hierarchy, generic params, IMgGridBase interface |
| `MGGRID/MGGRID_PARAMETERS.md` | Component parameters, event callbacks, default grid settings |
| `MGGRID/MGGRID_CRUD.md` | Lifecycle, CRUD operations, edit flow, disposal |
| `MGGRID/MGGRID_LAYOUT.md` | Layout persistence (storage keys, tiers, operations) |
| `MGGRID/MGGRID_DETAIL.md` | Master-detail hierarchy |
| `MGGRID/MGGRID_RENDERING.md` | Fullscreen mode, rendering |
| `MGGRID/MGGRID_INFOPANEL.md` | MgGridInfoPanel, MgGridWithInfoPanel wrapper |
| `MGGRID/MGGRID_TOOLBAR.md` | MgGridToolbarTemplate (buttons, parameters, state) |
| `MGGRID/MGGRID_COLUMNS.md` | MgGridDataColumn (InfoPanel params, UrlLink) |
| `MGGRID/MGGRID_DATASOURCE.md` | MgGridSignalRDataSource (server-side data, local cache) |
## Dependencies
- **DevExpress.Blazor** 25.1.3, **DevExpress.Data** 25.1.3
@ -39,3 +17,6 @@ Blazor Razor component library targeting .NET 10. Provides reusable DevExpress-b
- **`Components/`** -- DevExpress component wrappers and grid infrastructure.
- **`Services/`** -- Authentication, grid data source, and LINQ expression serialization helpers.
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -8,3 +8,6 @@ LINQ expression tree serialization and deserialization to JSON, enabling express
- **`AcExpressionHelper.cs`** -- Static facade for serializing/deserializing expressions and `IQueryable` query trees. Provides `ExpressionToJson`, `ExpressionFromJson`, `QueryToJson`, and `ApplyQueryFromJson` methods.
- **`AcExpressionSerializerVisitor.cs`** -- `ExpressionVisitor` subclass that walks an expression tree and builds the `AcExpressionNode` graph using a stack-based approach. Handles closure variable evaluation and constant serialization.
- **`AcExpressionDeserializer.cs`** -- Reconstructs `Expression` trees from `AcExpressionNode` DTOs. Resolves types, parameters, methods, and member bindings. Handles nullable type mismatches in binary expressions.
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -5,3 +5,6 @@ Web authentication service for the Blazor application.
## Key Files
- **`AcWebAuthService.cs`** -- `AcWebAuthService` class with a virtual `Logout()` method. Intended as a base class for application-specific auth services to override with concrete logout logic.
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -10,3 +10,6 @@ Application services including authentication, grid data source prototyping, and
- **`Logins/`** -- Web authentication service.
- **`ExpressionHelpers/`** -- LINQ expression tree serialization and deserialization to JSON for transport over SignalR or HTTP.
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -1,18 +0,0 @@
# MgGrid — Columns
> Part of the MgGrid system. See `README.md` for overview and component hierarchy.
## MgGridDataColumn
Extended `DxGridDataColumn` with InfoPanel and URL link support.
| Parameter | Type | Default | Description |
|---|---|---|---|
| `ShowInInfoPanel` | `bool` | `true` | Whether this column is visible in InfoPanel |
| `InfoPanelDisplayFormat` | `string?` | `null` | Custom display format for InfoPanel |
| `InfoPanelOrder` | `int` | `int.MaxValue` | Column order in InfoPanel (lower = earlier) |
| `UrlLink` | `string?` | `null` | URL template with `{Property}` placeholders |
**UrlLink example:** `https://admin.example.com/Entity/Edit/{Id}` — renders cell as `<a href="..." target="_blank">`.
Uses compiled property accessors (`ConcurrentDictionary` cache) for performance.

View File

@ -1,101 +0,0 @@
# MgGrid — Lifecycle & CRUD
> Part of the MgGrid system. See `README.md` for overview and component hierarchy.
## Lifecycle
```
1. OnInitializedAsync()
├── Validate Logger, SignalRClient (throw if null)
├── Create SignalRCrudTags from message tag parameters
├── Create TSignalRDataSource via Activator.CreateInstance(SignalRClient, crudTags, ContextIds)
├── Set DataSource.FilterText
├── Bind grid Data to data source inner list
└── Subscribe to: OnDataSourceLoaded, OnDataSourceItemChanged, OnSyncingStateChanged
2. SetParametersAsyncCore() [first time]
├── Set KeyFieldName = "Id"
├── Wire 6 DxGrid events → internal handlers (see MGGRID_PARAMETERS.md)
├── Add OnCustomizeElement handler (edit row highlighting, detail cell styling)
└── Set defaults: TextWrapEnabled=false, AllowSelectRowByClick=true, etc.
3. OnParametersSet() [first time]
├── Set GridName default: "{TDataItem.Name}Grid"
├── Set AutoSaveLayoutName default: "Grid{TDataItem.Name}"
├── Wire layout auto-loading/saving handlers
└── Register with GridWrapper via GridWrapper.RegisterGrid(this)
4. OnAfterRenderAsync(firstRender: true)
├── If DataSource parameter was provided: LoadDataSource(dataSourceParam, sync, notify)
└── Else: LoadDataSourceAsync(notify) — fires SignalR GetAll request
```
## CRUD Operations
### Adding Items
```csharp
await grid.AddDataItem(item); // local add, sync later
await grid.AddDataItemAsync(item); // immediate server sync
await grid.InsertDataItem(0, item); // insert at index, sync later
await grid.InsertDataItemAsync(0, item); // insert at index, immediate sync
```
### Other CRUD Methods
| Method | Description |
|---|---|
| `UpdateDataItem(item)` | Local update, sync later |
| `UpdateDataItemAsync(item)` | Immediate server sync |
| `AddOrUpdateDataItem(item)` | Add if new, update if existing |
| `RemoveDataItem(item)` | Remove by entity reference |
| `RemoveDataItem(id)` | Remove by ID |
| `ReloadDataSourceAsync()` | Re-fetch all data from server |
| `ForceRenderAsync()` | Force grid re-initialization via new render key |
### ID Generation for New Items
New items get **temporary client-side IDs** until the server assigns real ones:
| TId Type | Strategy | Example |
|---|---|---|
| `Guid` | `Guid.NewGuid()` | `a1b2c3d4-...` |
| `int` | `-1 * AcDomain.NextUniqueInt32` | `-1`, `-2`, `-3`, ... |
**Convention:** Negative integer IDs indicate unsaved items. The server replaces them with real auto-increment IDs.
### Edit Flow (Inline)
```
User clicks Edit → OnEditStart → OnCustomizeEditModel
├── Set GridEditState = New/Edit
├── For new items: assign temp ID, set parent FK if detail grid
├── Notify InfoPanel: SetEditMode()
└── Fire OnGridCustomizeEditModel callback
User clicks Save → OnItemSaving
├── Fire OnGridEditModelSaving callback (can cancel)
├── If new: AddDataItemAsync / InsertDataItemAsync
├── If existing: UpdateDataItemAsync
├── Reset GridEditState = None
└── Clear InfoPanel edit mode
User clicks Cancel → OnEditCanceling
├── Reset GridEditState = None
└── Clear InfoPanel edit mode
```
### Edit Row Highlighting
When `GridEditState != None`, the focused row and its cells get `background-color: #fffbeb` (warm yellow) via `OnCustomizeElement`.
## Disposal
`DisposeAsync()` handles cleanup:
1. Set `_isDisposed = true` (guards all async callbacks)
2. Unsubscribe from `OnDataSourceLoaded`, `OnDataSourceItemChanged`, `OnSyncingStateChanged`
3. Remove `OnCustomizeElement` handler
4. `GC.SuppressFinalize(this)`
All async callbacks check `_isDisposed` before proceeding.

View File

@ -1,13 +0,0 @@
# MgGrid — DataSource
> Part of the MgGrid system. See `README.md` for overview and component hierarchy.
> For the underlying `AcSignalRDataSource`: `AyCode.Services.Server/docs/SIGNALR_DATASOURCE/README.md` (in AyCode.Core repo)
## MgGridSignalRDataSource
`GridCustomDataSource` wrapper around `AcSignalRDataSource` for server-side data operations.
- Returns local data instantly for previously-seen filter criteria
- Refreshes from the server in the background
- Handles filter, sort, paging, unique values, and summary calculations locally
- `OnBackgroundRefreshCompleted` event fires when background refresh completes

View File

@ -1,25 +0,0 @@
# MgGrid — Master-Detail
> Part of the MgGrid system. See `README.md` for overview and component hierarchy.
## How It Works
1. `MgGridBase.BuildRenderTree` wraps content in `CascadingValue<IMgGridBase>`
2. Child grids receive this via `[CascadingParameter] IMgGridBase? ParentGrid`
3. `IsMasterGrid` = `ParentDataItem == null`
4. `GetRootGrid()` walks the `ParentGrid` chain to find the topmost grid
## Detail Grid Setup
```razor
<DetailRowTemplate>
@{
var parent = (ParentEntity)context.DataItem;
<GridChildEntity ParentDataItem="@parent"
KeyFieldNameToParentId="ParentEntityId"
ContextIds="@(new object[] { parent.Id })" />
}
</DetailRowTemplate>
```
When `ParentDataItem` is set and `KeyFieldNameToParentId` is provided, new items automatically get their parent FK set via reflection.

View File

@ -1,98 +0,0 @@
# MgGrid — InfoPanel
> Part of the MgGrid system. See `README.md` for overview and component hierarchy.
## MgGridWithInfoPanel Wrapper
```razor
<MgGridWithInfoPanel ShowInfoPanel="true" InfoPanelSize="400px">
<GridContent>
<GridMyEntityBase @ref="Grid" ... />
</GridContent>
<ChildContent>
@* Optional: custom InfoPanel — if omitted, default MgGridInfoPanel is used *@
</ChildContent>
</MgGridWithInfoPanel>
```
| Parameter | Type | Default | Description |
|---|---|---|---|
| `GridContent` | `RenderFragment` | — | The grid to display in the left pane |
| `ChildContent` | `RenderFragment?` | `null` | Custom InfoPanel. If `null`, renders `MgGridInfoPanel` |
| `ShowInfoPanel` | `bool` | `true` | Whether to show the right pane |
| `InfoPanelSize` | `string` | `"400px"` | Initial right pane size |
The wrapper provides:
- `DxSplitter` with collapsible right pane
- Fullscreen overlay (`mg-fullscreen-overlay`)
- Splitter size persistence (`Splitter_{key}` in localStorage)
- `RegisterGrid(grid)` — called by MgGridBase in `OnParametersSet`
- `RegisterInfoPanel(infoPanel)` — called by MgGridInfoPanel in `OnAfterRenderAsync`
## MgGridInfoPanel
Default InfoPanel component implementing `IInfoPanelBase`. Displays focused-row details with edit support.
### IInfoPanelBase Interface
```csharp
public interface IInfoPanelBase
{
void RefreshData(IMgGridBase grid, object? dataItem, int visibleIndex = -1);
void SetEditMode(IMgGridBase grid, object editModel);
void ClearEditMode();
}
```
### InfoPanel Data Flow
```
FocusedRowChanged → InfoPanelInstance.RefreshData(grid, dataItem, visibleIndex)
Edit starts → InfoPanelInstance.SetEditMode(grid, editModel)
Edit ends/cancel → InfoPanelInstance.ClearEditMode()
```
`InfoPanelInstance` resolution: own `GridWrapper.InfoPanelInstance` → root grid's `GridWrapper.InfoPanelInstance``null`.
### Responsive Column Layout
| Breakpoint Parameter | Default | Columns |
|---|---|---|
| — | < 400px | 1 column |
| `TwoColumnBreakpoint` | 400px | 2 columns |
| `ThreeColumnBreakpoint` | 800px | 3 columns |
| `FourColumnBreakpoint` | 1300px | 4 columns |
`FixedColumnCount` (1-4) overrides responsive breakpoints if set.
### Template System
| Template | Context | Purpose |
|---|---|---|
| `HeaderTemplate` | `InfoPanelContext` | Custom header (default: grid Caption) |
| `BeforeColumnsTemplate` | `InfoPanelContext` | Content before column-value pairs |
| `ColumnsTemplate` | `InfoPanelContext` | Replace default column rendering entirely |
| `AfterColumnsTemplate` | `InfoPanelContext` | Content after column-value pairs |
| `FooterTemplate` | `InfoPanelContext` | Custom footer |
`InfoPanelContext` = `record(object? DataItem, bool IsEditMode)`.
### Edit Mode Editors (by property type)
| Type | Editor Component |
|---|---|
| `bool` | `DxCheckBox<bool>` |
| `DateTime` / `DateTime?` | `DxDateEdit<DateTime>` / `DxDateEdit<DateTime?>` |
| `DateOnly` / `DateOnly?` | `DxDateEdit<DateOnly>` / `DxDateEdit<DateOnly?>` |
| `int` | `DxSpinEdit<int>` |
| `decimal` | `DxSpinEdit<decimal>` |
| `double` | `DxSpinEdit<double>` |
| ComboBox (via `DxComboBoxSettings`) | `DxComboBox<TValue, TItem>` |
| Memo (via `EditSettingsType.Memo`) | `DxMemo` |
| Other | `DxTextBox` |
### Additional Features
- **Sticky positioning** via JS interop (`MgGridInfoPanel.initSticky`)
- **Built-in toolbar** with `MgGridToolbarTemplate` (`OnlyGridEditTools=true`)
- **OnDataItemChanged** callback when focused row changes

View File

@ -1,27 +0,0 @@
# MGGRID — Known Issues
For planned/actionable work see `MGGRID_TODO.md`.
No formally-tracked issues yet. In-code TODOs are recorded as TODO entries (`ACBLAZOR-GRID-T-*`) in `MGGRID_TODO.md`, since they describe unfinished work rather than confirmed broken behaviour.
Add the first `## ACBLAZOR-GRID-I-XXXX: ...` entry below when a concrete issue is observed.
## Issue entry template
```
## ACBLAZOR-GRID-I-XXXX: Short title
**Severity:** Trivial / Low / Minor / Major · **Status:** Open / Documented / Mitigated · **Area:** <subsystem>
### Description
What breaks, and under what conditions.
### Root cause
Why it happens (code location + design mismatch).
### Known workaround
Steps a consumer can take until fixed.
### Related TODO
`MGGRID_TODO.md#acblazor-grid-t-XXXX` (if applicable).
```

View File

@ -1,46 +0,0 @@
# MgGrid — Layout Persistence
> Part of the MgGrid system. See `README.md` for overview and component hierarchy.
## Storage Keys
Grid layouts are stored in **localStorage** with structured keys:
```
AutoSave: {AutoSaveLayoutName}_{MasterOrParentTypeName}_AutoSave_{UserId}
UserSave: {AutoSaveLayoutName}_{MasterOrParentTypeName}_UserSave_{UserId}
Splitter: Splitter_{grid.AutomaticLayoutStorageKey}
```
**Examples:**
```
GridOrder_Master_AutoSave_42 ← master grid, user #42
GridOrder_Order_AutoSave_42 ← detail grid under Order parent
GridOrder_Master_UserSave_42 ← manually saved layout
Splitter_GridOrder_Master_AutoSave_42 ← splitter pane size
```
## Three Layout Tiers
| Tier | Key Contains | When Saved | When Loaded |
|---|---|---|---|
| **Default** | (in-memory `_defaultLayoutJson`) | First `LayoutAutoLoading` — captures layout before any load | `ResetLayoutAsync()` — restores original |
| **AutoSave** | `_AutoSave_` | Every `LayoutAutoSaving` event (on any layout change) | Every `LayoutAutoLoading` event (on grid init, wrapped in `BeginUpdate`/`EndUpdate`) |
| **UserSave** | `_UserSave_` | `SaveUserLayoutAsync()` — explicit user action | `LoadUserLayoutAsync()` — explicit user action |
## Layout Operations
| Method | Behavior |
|---|---|
| `SaveUserLayoutAsync()` | Saves current layout to both UserSave AND AutoSave keys |
| `LoadUserLayoutAsync()` | Loads from UserSave key (if exists) |
| `ResetLayoutAsync()` | Removes AutoSave key, restores in-memory `_defaultLayoutJson` |
| `HasUserLayoutAsync()` | Checks if UserSave key exists in localStorage |
## Persisted State
The layout (`GridPersistentLayout`) includes: column order, column widths, sort descriptors, group descriptors, filter row values, page size — serialized as JSON via `System.Text.Json`.
## User Identification
`GetLayoutUserId()` is virtual — defaults to `0`. Override in project adapter to provide the logged-in user's ID.

View File

@ -1,82 +0,0 @@
# MgGrid — Parameters & Events
> Part of the MgGrid system. See `README.md` for overview and component hierarchy.
## Required Parameters
| Parameter | Type | Description |
|---|---|---|
| `SignalRClient` | `AcSignalRClientBase` | SignalR client for server communication |
| `Logger` | `TLoggerClient` | Logger instance |
| `GetAllMessageTag` | `int` | SignalR tag for loading all items |
## CRUD Message Tags
| Parameter | Type | Description |
|---|---|---|
| `GetAllMessageTag` | `int` | Tag for "get all items" request |
| `GetItemMessageTag` | `int` | Tag for "get single item" request |
| `AddMessageTag` | `int` | Tag for "add item" request |
| `UpdateMessageTag` | `int` | Tag for "update item" request |
| `RemoveMessageTag` | `int` | Tag for "remove item" request |
These are bundled into a `SignalRCrudTags` during `OnInitializedAsync`. See `AyCode.Services.Server/docs/SIGNALR_DATASOURCE/README.md` (in AyCode.Core repo) for details.
## Data & Context Parameters
| Parameter | Type | Description |
|---|---|---|
| `DataSource` | `IList<TDataItem>` | Bind with `AcObservableCollection<TDataItem>` for external data. If not set, grid creates its own. |
| `ParentDataItem` | `IId<TId>?` | Parent entity for detail grids. `null` = master grid. |
| `KeyFieldNameToParentId` | `string?` | Property name on `TDataItem` that references the parent's ID |
| `ContextIds` | `object[]?` | Additional context passed to `AcSignalRDataSource` constructor |
| `FilterText` | `string?` | Text filter — propagated to data source, triggers reload |
## Display & Behavior Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| `Caption` | `string` | `typeof(TDataItem).Name` | Grid title (shown in fullscreen header) |
| `GridName` | `string` | `"{TDataItem.Name}Grid"` | Name used in log messages |
| `AutoSaveLayoutName` | `string?` | `"Grid{TDataItem.Name}"` | Base name for layout storage keys |
## Event Callbacks
All grid events are re-exposed with `OnGrid` prefix to avoid collisions with `DxGrid` base events:
| Event | DxGrid Equivalent | When Fired |
|---|---|---|
| `OnGridItemDeleting` | `DataItemDeleting` | Before item removal (can cancel via `e.Cancel`) |
| `OnGridEditModelSaving` | `EditModelSaving` | Before item save (can cancel via `e.Cancel`) |
| `OnGridEditStart` | `EditStart` | When edit mode begins |
| `OnGridCustomizeEditModel` | `CustomizeEditModel` | When edit model is being prepared |
| `OnGridFocusedRowChanged` | `FocusedRowChanged` | When focused row changes |
| `OnDataSourceChanged` | — | After data source is loaded/reloaded |
| `OnGridItemChanged` | — | After server confirms a CRUD operation |
| `OnGridItemChanging` | — | Before a CRUD operation is sent to server |
Internal event wiring (in `SetParametersAsyncCore`, first call):
| DxGrid Event | → Internal Handler |
|---|---|
| `DataItemDeleting` | `OnItemDeleting` |
| `EditModelSaving` | `OnItemSaving` |
| `CustomizeEditModel` | `OnCustomizeEditModel` |
| `FocusedRowChanged` | `OnFocusedRowChanged` |
| `EditStart` | `OnEditStart` |
| `EditCanceling` | `OnEditCanceling` |
## Default Grid Settings
Set in `SetParametersAsyncCore` (first call only):
| Setting | Value |
|---|---|
| `KeyFieldName` | `"Id"` |
| `TextWrapEnabled` | `false` |
| `AllowSelectRowByClick` | `true` |
| `HighlightRowOnHover` | `true` |
| `AutoCollapseDetailRow` | `true` |
| `AutoExpandAllGroupRows` | `false` |
Project adapters typically add more defaults in `OnParametersSet` (e.g., `EditMode`, `FocusedRowEnabled`, `PageSize`, `ShowFilterRow`, `SizeMode` based on `IsMasterGrid`).

View File

@ -1,21 +0,0 @@
# MgGrid — Fullscreen & Rendering
> Part of the MgGrid system. See `README.md` for overview and component hierarchy.
## Fullscreen Mode
Two modes depending on whether `MgGridWithInfoPanel` wraps the grid:
| Scenario | Behavior |
|---|---|
| **With wrapper** | `ToggleFullscreen()` delegates to wrapper — fullscreen includes grid + InfoPanel |
| **Standalone** | Grid renders its own `mg-fullscreen-overlay` with header (Caption + close button) and body |
## Rendering
`BuildRenderTree` uses manual render tree building (not Razor markup):
1. Outer `CascadingValue<IMgGridBase>` — provides this grid as `ParentGrid` to children
2. If standalone fullscreen: `div.mg-fullscreen-overlay` > `div.mg-fullscreen-header` + `div.mg-fullscreen-body` > `base.BuildRenderTree`
3. If normal: `div[style=display:contents]` > `base.BuildRenderTree`
4. `_gridRenderKey` (Guid) used as element key — changed by `ForceRenderAsync()` to force re-initialization

View File

@ -1,81 +0,0 @@
# MGGRID — TODO
For known issues / bugs see `MGGRID_ISSUES.md`.
## Priority legend
- **P0** blocker · **P1** important · **P2** nice-to-have · **P3** idea
---
## ACBLAZOR-GRID-T-V4P7: Generic ID generation in `MgGridBase.SetNewId`
**Priority:** P2 · **Type:** Refactor (framework-first) · **Origin:** 2026-04-24 in-code TODO audit · **Area:** `Components/Grids/MgGridBase.cs:460`
`SetNewId(TDataItem dataItem)` branches on `dataItem.Id is Guid` vs `dataItem.Id is int` to produce a new ID, and converts through `TypeConverter` back to `TId`. The in-code comment `//TODO: int !!! - J.` flags this as unfinished — the logic is not cleanly generic over `TId`.
```csharp
private void SetNewId(TDataItem dataItem)
{
//TODO: int !!! - J.
if (dataItem.Id is Guid)
{
dataItem.Id = (TId)(_typeConverterId.ConvertTo(Guid.NewGuid(), typeof(TId)))!;
}
else if (dataItem.Id is int)
{
var newId = -1 * AcDomain.NextUniqueInt32;
dataItem.Id = (TId)(_typeConverterId.ConvertTo(newId, typeof(TId)))!;
}
}
```
Problems:
- Runtime type switch on a generic parameter defeats the point of generics.
- Silent no-op for any other `TId` (e.g., `long`, `short`, custom struct) — no compile error, no throw.
- The negative-int convention (`-1 * AcDomain.NextUniqueInt32`) is not expressed as a contract; consumers cannot override.
### Fix options
- **(a)** Introduce `IAcNewIdGenerator<TId>` framework abstraction (in AyCode.Core) with default implementations for `Guid` and `int`. `MgGridBase` takes it via DI or generic parameter. Consumer-specific `TId` types register their generator.
- **(b)** Virtual protected method: `protected virtual TId GenerateNewId()` on `MgGridBase`, with default implementations for `Guid` and `int` preserved. Consumer overrides for custom `TId`.
- **(c)** Static strategy map keyed by `typeof(TId)` — registered once per app startup, resolved at runtime.
### Acceptance criteria
- No runtime type-switch in `MgGridBase`.
- Throws explicit `NotSupportedException` (or similar) for unregistered `TId` types.
- Existing `Guid` and `int` consumers unaffected.
- Remove the `//TODO: int !!! - J.` comment.
## ACBLAZOR-GRID-T-S2L9: Implement local grouping in `MgGridSignalRDataSource.GetGroupInfoAsync`
**Priority:** P3 · **Type:** Feature · **Origin:** 2026-04-24 in-code TODO audit · **Area:** `Components/Grids/MgGridSignalRDataSource.cs:202`
```csharp
public override async Task<IList<GridCustomDataSourceGroupInfo>> GetGroupInfoAsync(
GridCustomDataSourceGroupingOptions options,
CancellationToken cancellationToken)
{
_logger?.Debug("[MgGridSignalRDataSource] GetGroupInfoAsync");
// TODO: Implement local grouping when needed
return await base.GetGroupInfoAsync(options, cancellationToken);
}
```
Currently delegates to the DevExpress base implementation, which for a server-side `GridCustomDataSource` triggers a server round-trip. With `MgGridSignalRDataSource` already holding a local cache (see `MGGRID_DATASOURCE.md`), grouping over the cached rows would avoid that round-trip.
Not urgent — only light grouping usage so far; the base path works. Promote to P2 if a consumer hits perceptible grouping latency.
### Acceptance criteria
- Local grouping computed from the cached list when the full dataset is cached.
- Falls back to base (server) path when the cache is partial / paginated.
- Unit / integration test with a grouped column.
- Remove the `// TODO: Implement local grouping when needed` comment.
## TODO entry template
```
## ACBLAZOR-GRID-T-XXXX: Short title
**Priority:** P0 / P1 / P2 / P3 · **Type:** Bug fix / Feature / Refactor / Docs · **Related:** `MGGRID_ISSUES.md#acblazor-grid-i-XXXX` (if applicable)
Description of what and why, including the trigger (user request, audit finding, incident).
Options / sub-tasks / acceptance criteria.
```

View File

@ -1,39 +0,0 @@
# MgGrid — Toolbar
> Part of the MgGrid system. See `README.md` for overview and component hierarchy.
## MgGridToolbarTemplate
The standard toolbar rendered inside grid's `ToolbarTemplate`. Provides all standard grid operations.
### Toolbar Buttons
| Group | Buttons | Visible |
|---|---|---|
| **CRUD** | New, Edit, Delete | When NOT editing |
| **Edit mode** | Save, Cancel | When editing |
| **Navigation** | Prev Row, Next Row | When NOT editing |
| **Layout** | Column Chooser, Layout (Load/Save/Reset) | When `OnlyGridEditTools=false` |
| **Actions** | Export (CSV/XLSX/XLS/PDF), Reload Data, Fullscreen | When `OnlyGridEditTools=false` |
### Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| `Grid` | `IMgGridBase` | required | The grid to control |
| `OnlyGridEditTools` | `bool` | `false` | Show only CRUD + navigation (used by InfoPanel) |
| `ShowOnlyIcon` | `bool` | `false` | Hide button text, show only icons |
| `EnableNew` | `bool` | `true` | Enable "New" button |
| `EnableEdit` | `bool` | `true` | Enable "Edit" button |
| `EnableDelete` | `bool` | `false` | Enable "Delete" button |
| `ToolbarItemsExtended` | `RenderFragment?` | `null` | Extra toolbar items after standard buttons |
| `OnReloadDataClick` | `EventCallback` | — | Callback for "Reload Data" button |
### State Properties (computed from Grid)
| Property | Source |
|---|---|
| `IsEditing` | `Grid.GridEditState != MgGridEditState.None` |
| `IsSyncing` | `Grid.IsSyncing` |
| `HasFocusedRow` | `Grid.GetFocusedRowIndex() >= 0` |
| `IsFullscreenMode` | `Grid.IsFullscreen` |

View File

@ -1,118 +0,0 @@
# MgGrid System
> Comprehensive documentation for the **MgGrid** component family — the primary UI data grid pattern in the AyCode.Blazor framework.
> Source: `Components/Grids/`
> For SignalR transport: `AyCode.Services/docs/SIGNALR/README.md` (in AyCode.Core repo)
> For `AcSignalRDataSource`: `AyCode.Services.Server/docs/SIGNALR_DATASOURCE/README.md` (in AyCode.Core repo)
## Overview
**MgGridBase** is an abstract generic Blazor component that extends DevExpress `DxGrid` with:
- **Automatic SignalR CRUD** via `AcSignalRDataSource` (see AyCode.Core docs)
- **Layout persistence** — column order, widths, sorting, grouping auto-saved to `localStorage`
- **Master-detail hierarchy** — nested grids share context via `CascadingParameter`
- **InfoPanel integration** — side panel shows focused row details, supports edit mode
- **Fullscreen mode** — standalone overlay or via `MgGridWithInfoPanel` wrapper
- **Change tracking** — client-side tracking with server sync via `SaveChangesAsync`
## Detailed Documentation
| File | Topics |
|---|---|
| `MGGRID_PARAMETERS.md` | Component parameters (required, CRUD tags, data & context, display), event callbacks, default grid settings |
| `MGGRID_CRUD.md` | Lifecycle, CRUD operations, ID generation, edit flow, disposal |
| `MGGRID_LAYOUT.md` | Layout persistence (storage keys, three tiers, operations, persisted state) |
| `MGGRID_DETAIL.md` | Master-detail hierarchy |
| `MGGRID_RENDERING.md` | Fullscreen mode, rendering |
| `MGGRID_INFOPANEL.md` | MgGridInfoPanel, MgGridWithInfoPanel wrapper, responsive layout, templates, editors |
| `MGGRID_TOOLBAR.md` | MgGridToolbarTemplate (buttons, parameters, state) |
| `MGGRID_COLUMNS.md` | MgGridDataColumn (InfoPanel params, UrlLink) |
| `MGGRID_DATASOURCE.md` | MgGridSignalRDataSource (server-side data, local cache, background refresh) |
| `MGGRID_ISSUES.md` | Known issues (`ACBLAZOR-GRID-I-*`, `ACBLAZOR-GRID-B-*`) — currently none formally tracked |
| `MGGRID_TODO.md` | Planned work (`ACBLAZOR-GRID-T-*`) — refactors, missing features, optimizations |
## Component Hierarchy
```
DxGrid (DevExpress)
└── MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClient> (AyCode.Blazor — abstract)
└── [Project-specific adapter] ← consumer fixes TSignalRDataSource, TId, TLoggerClient
└── [Concrete entity grid] ← consumer sets CRUD tags in constructor
```
### Companion Components
| Component | Purpose | Docs |
|---|---|---|
| **MgGridWithInfoPanel** | `DxSplitter` wrapper: grid + InfoPanel, fullscreen, splitter persistence | `MGGRID_INFOPANEL.md` |
| **MgGridToolbarBase** | `DxToolbar` base with `Grid` reference, `RefreshClick` callback | `MGGRID_TOOLBAR.md` |
| **MgGridToolbarTemplate** | Full toolbar: CRUD, navigation, layout menu, fullscreen, export | `MGGRID_TOOLBAR.md` |
| **MgGridDataColumn** | Extended `DxGridDataColumn` with InfoPanel params and `UrlLink` | `MGGRID_COLUMNS.md` |
| **MgGridInfoPanel** | Default InfoPanel: column-value pairs, edit mode, typed editors | `MGGRID_INFOPANEL.md` |
| **MgGridSignalRDataSource** | `GridCustomDataSource` wrapper: server-side filter/sort/page, local cache | `MGGRID_DATASOURCE.md` |
## Generic Type Parameters
```csharp
MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClient>
```
| Parameter | Constraint | Purpose |
|---|---|---|
| `TSignalRDataSource` | `: AcSignalRDataSource<…>` | SignalR-backed data source (see `AyCode.Services.Server/docs/SIGNALR_DATASOURCE/README.md` in AyCode.Core repo) |
| `TDataItem` | `: class, IId<TId>` | Entity type displayed in the grid |
| `TId` | `: struct` | Primary key type (`int`, `Guid`) |
| `TLoggerClient` | `: AcLoggerBase` | Logger for diagnostics |
### Usage Example (Project-Specific Adapter)
```csharp
// Project adapter — fixes TSignalRDataSource, TId, TLoggerClient for the entire project
public class MyProjectGridBase<TDataItem>
: MgGridBase<MySignalRDataSource<TDataItem>, TDataItem, int, MyLoggerClient>
where TDataItem : class, IId<int>
{
[Inject] public required MyLoggedInModel LoggedInModel { get; set; }
protected override int GetLayoutUserId() => LoggedInModel.UserId;
}
// Concrete grid — only TDataItem remains open
public class GridOrderBase : MyProjectGridBase<Order>
{
public GridOrderBase()
{
GetAllMessageTag = MySignalRTags.GetOrders;
AddMessageTag = MySignalRTags.AddOrder;
UpdateMessageTag = MySignalRTags.UpdateOrder;
}
}
```
## Interface: IMgGridBase
The public contract exposed to companion components (toolbar, InfoPanel, wrapper):
| Member | Type | Description |
|---|---|---|
| `IsSyncing` | `bool` | Whether SignalR sync is in progress |
| `Caption` | `string` | Grid title |
| `GridEditState` | `MgGridEditState` | `None` / `New` / `Edit` |
| `ParentGrid` | `IMgGridBase?` | Parent in master-detail hierarchy |
| `GetRootGrid()` | `IMgGridBase` | Walks to topmost grid |
| `StepPrevRow()` | `void` | Navigate to previous visible row |
| `StepNextRow()` | `void` | Navigate to next visible row |
| `InfoPanelInstance` | `IInfoPanelBase?` | Resolved InfoPanel reference |
| `IsFullscreen` | `bool` | Current fullscreen state |
| `AutomaticLayoutStorageKey` | `string` | Current auto-save storage key |
| `ToggleFullscreen()` | `void` | Toggle fullscreen mode |
| `SaveUserLayoutAsync()` | `Task` | Save layout manually |
| `LoadUserLayoutAsync()` | `Task` | Load manually saved layout |
| `ResetLayoutAsync()` | `Task` | Reset to default layout |
| `HasUserLayoutAsync()` | `Task<bool>` | Check if manual save exists |
## Event Args Classes
| Class | Base | Extra Properties |
|---|---|---|
| `GridDataItemChangedEventArgs<T>` | — | `Grid`, `DataItem`, `TrackingState`, `CancelStateChangeInvoke` |
| `GridDataItemChangingEventArgs<T>` | `GridDataItemChangedEventArgs<T>` | `IsCanceled` |

View File

@ -1,16 +0,0 @@
# AyCode.Blazor.Components documentation
Topic documentation for the `AyCode.Blazor.Components` project (Blazor component library).
## Topics
- [`MGGRID/`](MGGRID/README.md) — MGGRID data grid component family (CRUD, layout, columns, toolbar, rendering, etc.)
## Navigation
Per the AI Agent Core Protocol (folder navigation rule), start from this README when browsing `docs/`. Each topic folder has its own `README.md` with the main content, plus `TOPIC_*.md` sub-topic files.
## See also
- **Blazor repo conventions**: `../../docs/CONVENTIONS.md`
- **Architecture overview**: `../../docs/ARCHITECTURE.md`

View File

@ -1,12 +1,5 @@
# AyCode.Blazor.Controllers
@project {
type = "framework"
own-dep-projects = [
"AyCode.Core, AyCode.Core.Server, AyCode.Database, AyCode.Entities, AyCode.Entities.Server, AyCode.Interfaces, AyCode.Interfaces.Server, AyCode.Models, AyCode.Models.Server, AyCode.Services, AyCode.Services.Server, AyCode.Utils (in AyCode.Core repo)"
]
}
Scaffolding project for Blazor controllers and logging infrastructure. Currently contains only a placeholder class with a reserved folder for future logger implementations.
## Key Files
@ -25,3 +18,6 @@ Scaffolding project for Blazor controllers and logging infrastructure. Currently
| Microsoft.AspNetCore.SignalR.Client | 9.0.11 | NuGet |
| Microsoft.AspNetCore.SignalR.Common | 9.0.11 | NuGet |
| AyCode.Core, .Core.Server, .Database, .Entities, .Entities.Server, .Interfaces, .Interfaces.Server, .Models, .Models.Server, .Services, .Services.Server, .Utils | -- | DLL references |
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -1,12 +1,5 @@
# AyCode.Blazor.Models.Server
@project {
type = "framework"
own-dep-projects = [
"AyCode.Core, AyCode.Core.Server, AyCode.Database, AyCode.Entities, AyCode.Entities.Server, AyCode.Interfaces, AyCode.Interfaces.Server, AyCode.Models.Server, AyCode.Services, AyCode.Services.Server, AyCode.Utils (in AyCode.Core repo)"
]
}
Scaffolding project for server-side Blazor models and services. Currently contains only a placeholder class with reserved folders for future implementation.
## Key Files
@ -31,3 +24,6 @@ Scaffolding project for server-side Blazor models and services. Currently contai
| AyCode.Services | DLL reference |
| AyCode.Services.Server | DLL reference |
| AyCode.Utils | DLL reference |
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -1,12 +1,5 @@
# AyCode.Blazor.Models
@project {
type = "framework"
own-dep-projects = [
"AyCode.Core, AyCode.Core.Server, AyCode.Entities, AyCode.Entities.Server, AyCode.Interfaces, AyCode.Interfaces.Server, AyCode.Models, AyCode.Models.Server, AyCode.Services, AyCode.Services.Server, AyCode.Utils (in AyCode.Core repo)"
]
}
.NET 10 class library with AOT compilation (`RunAOTCompilation` + `WasmStripILAfterAOT`) providing view model base classes and shared models for the AyCode Blazor UI layer.
## Key Files
@ -31,3 +24,6 @@ All referenced as pre-built DLLs from `AyCode.Core\AyCode.Services.Server\bin\`:
| AyCode.Services | DLL reference |
| AyCode.Services.Server | DLL reference |
| AyCode.Utils | DLL reference |
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -20,3 +20,6 @@ AcViewModelBase
AcDomainViewModel
+-- AcSiteViewModel
```
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -11,3 +11,6 @@ Platform-specific code for AyCode.Maui.Core. Each subfolder is conditionally com
## Key Files
- **`{Platform}/PlatformClass1.cs`** -- Empty placeholder class per platform, all in the `AyCode.Maui.Core` namespace.
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -1,12 +1,5 @@
# AyCode.Maui.Core
@project {
type = "framework"
own-dep-projects = [
"AyCode.Core, AyCode.Entities, AyCode.Interfaces, AyCode.Models, AyCode.Services, AyCode.Utils (in AyCode.Core repo)"
]
}
.NET MAUI class library targeting Android (API 33+), iOS (15.0+), and Windows (10.0.19041+). Provides cross-platform shared code with per-platform specialization via the `Platforms/` folder.
## Key Files
@ -23,3 +16,6 @@
| Microsoft.AspNetCore.SignalR.Common | 9.0.11 | NuGet |
| MessagePack | 3.1.4 | NuGet |
| AyCode.Core, .Entities, .Interfaces, .Models, .Services, .Utils | -- | DLL references |
---
> **LLM Maintenance:** If you modify code in this folder, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -18,16 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
AyCode.Blazor.targets = AyCode.Blazor.targets
AyCode.Maui.targets = AyCode.Maui.targets
AyCode.Project.targets = AyCode.Project.targets
.github\copilot-instructions.md = .github\copilot-instructions.md
CLAUDE.md = CLAUDE.md
README.md = README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{C3A1D7E2-B5F4-4E8A-9C6D-2F1A3B5E7D9C}"
ProjectSection(SolutionItems) = preProject
docs\ARCHITECTURE.md = docs\ARCHITECTURE.md
docs\CONVENTIONS.md = docs\CONVENTIONS.md
docs\GLOSSARY.md = docs\GLOSSARY.md
EndProjectSection
EndProject
Global

View File

@ -1,17 +1,10 @@
CRITICAL: Your FIRST action in every session MUST be reading `.github/copilot-instructions.md`. Execute ALL session-start instructions found there before responding to any user query. It is the single source of truth for this repo.
# AyCode.Blazor — Claude Code Instructions
## SEQUENTIAL EXECUTION OVERRIDE
The AI AGENT CORE PROTOCOL in copilot-instructions.md requires STRICT SEQUENTIAL execution. This OVERRIDES your default parallelization behavior. Do NOT parallelize doc reads with code searches. The sequence is:
1. Read copilot-instructions.md → process its rules FULLY
2. Read ALL docs/ .md files listed in the protocol → wait for completion
3. Output [LOADED_DOCS: ...] prefix
4. ONLY THEN respond to the user's query or search code
Before writing any code, read these files:
1. `.github/copilot-instructions.md` — Domain rules and UI pitfalls (single source of truth)
2. `docs/GLOSSARY.md` — Blazor/MAUI terminology and DevExpress conventions
3. The relevant project's `README.md` for folder-specific context
## Tool mapping for AI AGENT CORE PROTOCOL
The copilot-instructions.md references Copilot tool names. Map them to Claude Code tools:
- `get_file` / `file_search``Read`, `Glob`, `Grep`
- `code_search` / `get_symbols_by_name` / `find_symbol``Grep`, `Glob`
- `replace_string_in_file` / `edit_file``Edit`
- `create_file``Write`
This solution depends on **AyCode.Core** — for core framework rules see `../AyCode.Core/CLAUDE.md`.
Follow the protocol using YOUR tools. The rules (LOADED_DOCS prefix, hard-gate, no-re-read, context recovery, explicit consent) apply equally to Claude Code.
When modifying code, update the corresponding README.md if it becomes out of sync with the code.

View File

@ -1,10 +1,10 @@
# AyCode.Blazor Solution
Blazor Server + MAUI Hybrid UI framework built on DevExpress 25.1.3 components. Targets **net10.0** (AyCode.Project.targets). Provides reusable grids, card views, authentication, and SignalR-powered real-time data. Depends on AyCode.Core (net9.0) for serialization, entities, and services — referenced via DLL.
Blazor Server + MAUI Hybrid UI framework built on DevExpress 25.1.3 components. Provides reusable grids, card views, authentication, and SignalR-powered real-time data. Depends on AyCode.Core for serialization, entities, and services.
## LLM Context
Domain rules and UI pitfalls live in a single file: `.github/copilot-instructions.md`
Domain rules and UI pitfalls live in a single file: [`.github/copilot-instructions.md`](.github/copilot-instructions.md)
| Tool | Auto-loaded | Action needed |
|------|------------|---------------|
@ -12,34 +12,26 @@ Domain rules and UI pitfalls live in a single file: `.github/copilot-instruction
| Claude Code | ✅ `CLAUDE.md` → references above | None |
| Cursor / Windsurf | ✅ `README.md` | Read `copilot-instructions.md` via @file |
Solution-level docs in `docs/`:
Detailed docs: [`docs/`](docs/) — GLOSSARY.md, ARCHITECTURE.md
| Document | Topic |
|---|---|
| `GLOSSARY.md` | Blazor/MAUI terminology |
| `ARCHITECTURE.md` | Solution layers, dependency rules |
| `CONVENTIONS.md` | Coding conventions |
Project-level docs:
| Project | Documents |
|---|---|
| `AyCode.Blazor.Components/docs/` | `MGGRID/` — MgGrid system (grid base, toolbar, InfoPanel, layout, CRUD) |
Core framework rules: `../AyCode.Core/.github/copilot-instructions.md`
Core framework rules: [`../AyCode.Core/.github/copilot-instructions.md`](../AyCode.Core/.github/copilot-instructions.md)
## Solution Structure
| Project | Purpose |
|---|---|
| `AyCode.Blazor.Components` | DevExpress UI components, grids, SignalR data sources, expression helpers |
| `AyCode.Blazor.Models` | Shared view models for Blazor components |
| `AyCode.Blazor.Models.Server` | Server-side model scaffolding |
| `AyCode.Blazor.Controllers` | Controller scaffolding (minimal) |
| `AyCode.Maui.Core` | MAUI cross-platform: Android, iOS, Windows |
| Project | Purpose | README |
|---|---|---|
| [`AyCode.Blazor.Components`](AyCode.Blazor.Components/README.md) | DevExpress UI components, grids, SignalR data sources, expression helpers | [README](AyCode.Blazor.Components/README.md) |
| [`AyCode.Blazor.Models`](AyCode.Blazor.Models/README.md) | Shared view models for Blazor components | [README](AyCode.Blazor.Models/README.md) |
| [`AyCode.Blazor.Models.Server`](AyCode.Blazor.Models.Server/README.md) | Server-side model scaffolding | [README](AyCode.Blazor.Models.Server/README.md) |
| [`AyCode.Blazor.Controllers`](AyCode.Blazor.Controllers/README.md) | Controller scaffolding (minimal) | [README](AyCode.Blazor.Controllers/README.md) |
| [`AyCode.Maui.Core`](AyCode.Maui.Core/README.md) | MAUI cross-platform: Android, iOS, Windows | [README](AyCode.Maui.Core/README.md) |
### Test Projects
| Project | Purpose |
|---|---|
| `AyCode.Blazor.Components.Tests` | Grid and component tests |
| Project | Purpose | README |
|---|---|---|
| [`AyCode.Blazor.Components.Tests`](AyCode.Blazor.Components.Tests/README.md) | Grid and component tests | [README](AyCode.Blazor.Components.Tests/README.md) |
---
> **LLM Maintenance:** If you modify this solution's structure, update this README to reflect the changes. If you notice the README content does not match the current code, automatically update the README to match the code.

View File

@ -1,20 +1,9 @@
# Architecture
## Framework vs. Consumer Boundary
This is **Layer 1 — UI framework**, building on Layer 0 (AyCode.Core) and consumed by Layer 2/3 projects. Full doctrine: `../AyCode.Core/docs/ARCHITECTURE.md#framework-vs-consumer-boundary`.
### Blazor/MAUI-specific notes
- Components use **generic type parameters** for consumer types (e.g. the MgGrid generic hierarchy)
- DevExpress wrappers stay generic — no consumer-entity specialization in framework components
- MAUI platform folders (`AyCode.Maui.Core/Platforms/`) provide platform abstractions only; consumer-app manifest / splash screens / app-specific assets belong in the consumer app
- UI patterns maximize **generic base + consumer derives**
## Dependency Graph
```
AyCode.Core Solution ../AyCode.Core/AyCode.Core.sln (DLL references)
AyCode.Core Solution (DLL references)
AyCode.Blazor.Models ← AyCode.Blazor.Models.Server
@ -24,7 +13,6 @@ AyCode.Maui.Core (MAUI Hybrid host)
```
**Rule:** UI projects reference AyCode.Core via DLL (not ProjectReference). This separates build graphs.
**Context:** When a core type is not found in this solution, browse `../AyCode.Core/` for its definition.
## How It Works
@ -47,29 +35,13 @@ User → DxGrid → AcSignalRDataSource → SignalR (AcBinary) → Server Hub
User ← DxGrid ← AcSignalRDataSource ← SignalR (AcBinary) ← Server Hub
```
## MgGrid Component System
The primary UI pattern for data screens. Overview and index: `AyCode.Blazor.Components/docs/MGGRID/README.md`
```
DxGrid (DevExpress)
└── MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClient>
└── [Project adapter, e.g. FruitBankGridBase<TDataItem>]
└── [Concrete grid, e.g. GridShippingBase]
```
| Component | Role |
|---|---|
| **MgGridBase** | Abstract base — SignalR CRUD, layout persistence, master-detail, edit state |
| **MgGridWithInfoPanel** | `DxSplitter` wrapper — grid + collapsible InfoPanel + fullscreen |
| **MgGridToolbarTemplate** | Full toolbar: CRUD, navigation, layout, export, fullscreen |
| **MgGridDataColumn** | `DxGridDataColumn` with InfoPanel parameters and URL template support |
| **MgGridInfoPanel** | Default InfoPanel — column-value display with edit mode |
| **MgGridSignalRDataSource** | `GridCustomDataSource` with local cache and background refresh |
## Key Design Decisions
- **DevExpress 25.1.3** exclusively — no mixing with other component libraries
- **SignalR over REST** for grid data — enables real-time updates and binary protocol
- **Expression serialization** — grid filters evaluated server-side, not client-side
- **Shared components** — Blazor Server and MAUI Hybrid use the exact same component library
---
> **LLM Maintenance:** If you modify the architecture, update this document.

View File

@ -1,15 +1,6 @@
# Conventions
For core framework conventions (Ac prefix, Session/Transaction pattern, etc.) see `AyCode.Core/docs/CONVENTIONS.md`.
## Framework-First Placement
Follow the doctrine in `../AyCode.Core/docs/CONVENTIONS.md#framework-first-placement`. Same verdicts and hard rules apply.
**Blazor/MAUI-specific additions:**
- UI types follow the generic-base pattern — consumer types are type parameters, not hardcoded concrete types
- DevExpress-wrapper components stay generic across consumers
- MAUI platform code = platform abstractions only, not consumer-app specifics
For core framework conventions (Ac prefix, Session/Transaction pattern, etc.) see [`../../AyCode.Core/docs/CONVENTIONS.md`](../../AyCode.Core/docs/CONVENTIONS.md).
## Naming
@ -18,10 +9,6 @@ Follow the doctrine in `../AyCode.Core/docs/CONVENTIONS.md#framework-first-place
- **Services:** `Ac{Domain}ServiceBase` for abstract bases. Platform-specific implementations in consuming projects.
- **ViewModels:** In `AyCode.Blazor.Models/ViewModels/` — suffixed with `ViewModel` or kept as plain model classes.
## XML Documentation
`<summary>` — brief, developer-facing, readable in VS IntelliSense tooltip. NO implementation details, NO wire-format / byte-level / perf specifics — those live in `docs/TOPIC/*.md`. Add `<example>` only when usage is non-obvious; otherwise omit.
## Component Patterns
- **DevExpress 25.1.3 exclusively** — never mix with other Blazor component libraries.
@ -46,3 +33,13 @@ Follow the doctrine in `../AyCode.Core/docs/CONVENTIONS.md#framework-first-place
- All AyCode.Core project references are via **DLL** (not ProjectReference) — this is intentional to separate build graphs.
- DevExpress references are NuGet packages pinned to **25.1.3**.
## Critical Rules
- Do not suggest removal/rollback as a solution — find a fix for the problem.
- SignalR uses **AcBinaryHubProtocol** — never switch to default JSON protocol.
- Grid data always flows through SignalR, never direct REST calls.
---
> **LLM Maintenance:** If you establish new UI conventions or patterns, document them here.

View File

@ -1,6 +1,6 @@
# Glossary
Blazor/MAUI UI terminology. For core framework terms see `AyCode.Core/docs/GLOSSARY.md`.
Blazor/MAUI UI terminology. For core framework terms see [`../../AyCode.Core/docs/GLOSSARY.md`](../../AyCode.Core/docs/GLOSSARY.md).
## UI Components
@ -8,28 +8,9 @@ Blazor/MAUI UI terminology. For core framework terms see `AyCode.Core/docs/GLOSS
|---|---|
| **DxGrid** | DevExpress Blazor data grid. Used with `AcSignalRDataSource` for real-time SignalR data. |
| **CardView** | Card-style layout wrapping DxGrid. Mobile-friendly alternative to table grids. |
| **AcSignalRDataSource** | Grid data source backed by SignalR. Handles load, CRUD, filtering, and change tracking. See `AyCode.Services.Server/docs/SIGNALR_DATASOURCE/README.md` in AyCode.Core repo. |
| **AcSignalRDataSource** | Grid data source backed by SignalR. Handles load, CRUD, filtering, and change tracking. |
| **AcExpressionNode** | Serializable LINQ expression tree. Grid filters are serialized as expression nodes and sent to server. |
## MgGrid System
For full technical reference see `AyCode.Blazor.Components/docs/MGGRID/README.md`.
| Term | Definition |
|---|---|
| **MgGridBase** | Abstract generic grid component extending `DxGrid` with SignalR CRUD, layout persistence, master-detail, InfoPanel, fullscreen. |
| **MgGridWithInfoPanel** | `DxSplitter` wrapper: grid (left pane) + InfoPanel (right pane), fullscreen overlay, splitter size persistence. |
| **MgGridToolbarBase** | `DxToolbar` base with `Grid` (`IMgGridBase`) reference and `RefreshClick` callback. |
| **MgGridToolbarTemplate** | Full toolbar: New/Edit/Delete/Save/Cancel, row navigation, layout menu, export, fullscreen. Extensible via `ToolbarItemsExtended`. |
| **MgGridDataColumn** | Extended `DxGridDataColumn` with InfoPanel parameters and `UrlLink` template (`{Property}` placeholders). |
| **MgGridInfoPanel** | Default InfoPanel: column-value pairs for focused row, responsive columns, edit mode with typed editors, template system. |
| **MgGridSignalRDataSource** | `GridCustomDataSource` wrapping `AcSignalRDataSource`. Local cache, background refresh. |
| **IMgGridBase** | Public interface: `IsSyncing`, `GridEditState`, `ParentGrid`, `StepPrevRow/NextRow`, layout persistence methods. |
| **MgGridEditState** | Enum: `None` (no edit), `New` (adding item), `Edit` (modifying item). |
| **SignalRCrudTags** | Bundle of 5 integer message tags (GetAll, GetItem, Add, Update, Remove) for one entity type. See `AyCode.Services.Server/docs/SIGNALR_DATASOURCE/README.md` in AyCode.Core repo. |
| **IsMasterGrid** | `true` when `ParentDataItem == null` — top-level grid (not detail). |
| **AutoSaveLayoutName** | Base name for localStorage layout keys. Default: `"Grid{TDataItem.Name}"`. |
## Architecture
| Term | Definition |
@ -51,3 +32,7 @@ For full technical reference see `AyCode.Blazor.Components/docs/MGGRID/README.md
|---|---|
| **Platforms/** | Per-platform code folders: Android, iOS, Windows. MAUI SDK auto-includes based on target. |
| **API 33+** | Minimum Android API level (Android 13). |
---
> **LLM Maintenance:** If you modify code that changes terminology, update this glossary.

View File

@ -1,23 +0,0 @@
# AyCode.Blazor documentation
Top-level documentation for the `AyCode.Blazor` repo (Blazor/MAUI UI framework — Layer 1).
## Reference docs (flat)
- [`ARCHITECTURE.md`](ARCHITECTURE.md) — Repo architecture overview
- [`CONVENTIONS.md`](CONVENTIONS.md) — Coding conventions
- [`GLOSSARY.md`](GLOSSARY.md) — Domain glossary
## Topic folders
Topic-specific documentation lives at the sub-project level:
- **MGGRID** (data grid component family): `../AyCode.Blazor.Components/docs/MGGRID/README.md`
## Navigation
Per the AI Agent Core Protocol (folder navigation rule), start from this README when browsing `docs/`. Single-file reference docs remain flat at this level; multi-file topics live in named subfolders.
## See also
- **Base framework docs**: `../../AyCode.Core/docs/README.md` (if present) and per-project `docs/` folders under AyCode.Core.