4.1 KiB
Bank Composition Editor
Original Problem
Bank Composition needed to become a real editor inside Asset Details without collapsing into any of these bad outcomes:
- direct binding to raw snapshot or manifest shapes;
- overgeneric UI components before the first section existed;
- family-specific rules hidden inside visual controls;
- direct Studio writes to
asset.json; - public bus chatter for every local section interaction.
Consolidated Decision
The first-wave Bank Composition model is:
- Studio owns a DTO projection boundary for the section;
- the section shell lands early and follows the existing staged-edit rhythm;
- dual-list and capacity-meter components stay intentionally dumb;
- one section-scoped coordinator around
StudioFormSession<BankCompositionDraft>owns orchestration; - public workspace-bus events stay minimal and notification-oriented;
applygoes through packer and rebinds from refreshed persisted state.
Final Model
1. DTO Boundary
The section never consumes raw packer/runtime structures directly.
It works with Studio-owned DTOs for:
availablerows from current runtime/details state;selectedrows from persisted composition state.
Only non-blocking files enter the available DTO projection.
2. Section Shell
Bank Composition is a real Asset Details section, not a hidden future placeholder.
The shell follows the existing staged-edit rhythm:
changeapplyresetcancel
Outside edit mode, it teaches the current persisted state in read-only form.
3. Dumb Components
Two named components exist for this area:
StudioDualListView<T>StudioAssetCapacityMeter
They are intentionally state-driven, not rule-driven. Family-specific transfer, ordering, and capacity semantics do not live inside these components.
4. Section-Scoped Coordinator
The main orchestration lives in one section-scoped coordinator built around StudioFormSession<BankCompositionDraft>.
That coordinator owns:
- draft lifecycle;
- transfer and reorder effects;
- capacity state;
- blockers and hints;
- apply success and failure handling.
5. WorkspaceBus Boundary
The public bus surface stays intentionally small.
First-wave public notifications are about observable state transitions:
- draft changed;
- capacity changed;
- apply requested;
- apply succeeded;
- apply failed.
Local edit actions remain local to the section coordinator.
6. Persistence Boundary
Studio does not write asset.json directly for Bank Composition.
The write path is:
- Studio submits ordered selected files to packer;
- packer validates and persists through
asset.json.artifacts; - packer refreshes the minimum runtime/details state;
- Studio rebinds from refreshed persisted state.
If apply fails, the draft stays alive and the section remains in editing mode.
Examples
Example: Why the meter must stay dumb
Tile banks and sound banks may calculate capacity differently.
That difference belongs in family policies owned by the coordinator, not in StudioAssetCapacityMeter.
Example: Why apply is not a public bus command
External observers may care that apply was requested or failed.
They do not need to own the local section command sequence for moveUp, moveDown, reset, or cancel.
Common Pitfalls and Anti-Patterns
- Binding section UI directly to raw snapshot rows or raw manifest shape.
- Hiding bank-family rules inside
StudioDualListView<T>or the capacity meter. - Creating a second staged-edit session model parallel to
StudioFormSession. - Turning every local section action into a public workspace-bus event.
- Writing
asset.jsondirectly from Studio instead of routing through packer.