Add custom section registration API for team settings view#42
Add custom section registration API for team settings view#42anilcancakir wants to merge 4 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an extensibility API that lets host apps register additional “cards/sections” in the Teams Settings view without overriding the entire view.
Changes:
- Introduces
MagicStarterTeamSettingsSectionRegistry+ section definition model to register/remove/sort custom sections. - Exposes the registry via
MagicStarter.teamSettings(wired throughMagicStarterManager) and renders registered sections in the team settings view. - Adds docs/examples (README + docs) and a dedicated unit test for the registry behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/ui/magic_starter_team_settings_section_registry_test.dart | Adds unit tests for registering/removing/sorting custom team settings sections. |
| README.md | Documents MagicStarter.teamSettings.registerSection(...) usage. |
| lib/src/ui/views/teams/magic_starter_team_settings_view.dart | Renders registered custom sections after built-in sections. |
| lib/src/ui/magic_starter_team_settings_section_registry.dart | New registry + section definition types for custom team settings sections. |
| lib/src/magic_starter_manager.dart | Stores the registry on the manager and clears it on reset. |
| lib/src/facades/magic_starter.dart | Exposes the registry via MagicStarter.teamSettings. |
| lib/magic_starter.dart | Exports the new registry API publicly. |
| doc/basics/teams.md | Adds a “Custom Sections” guide with examples and notes. |
| doc/architecture/manager.md | Updates facade ↔ manager mapping documentation. |
| CHANGELOG.md | Notes the new Team Settings Sections feature under Unreleased. |
| /// All registered custom sections, sorted by [order] ascending. | ||
| /// | ||
| /// Sections with equal order values preserve insertion order (stable sort). | ||
| List<MagicStarterTeamSettingsSection> get sections { | ||
| return _sections.values.toList() | ||
| ..sort((a, b) => a.order.compareTo(b.order)); | ||
| } |
There was a problem hiding this comment.
sections claims (and tests rely on) a stable sort for equal order values, but List.sort in Dart is not guaranteed to be stable. This means sections with the same order may render in non-deterministic order depending on the sort implementation. To guarantee insertion-order tie-breaking, track a sequence/index at registration time and sort by (order, sequence) (or remove the stability promise and update docs/tests accordingly).
| test('stable sort — equal order preserves insertion order', () { | ||
| registry.registerSection( | ||
| key: 'alpha', | ||
| order: 10, | ||
| builder: (_, __) => const SizedBox(), | ||
| ); | ||
|
|
||
| registry.registerSection( | ||
| key: 'beta', | ||
| order: 10, | ||
| builder: (_, __) => const SizedBox(), | ||
| ); | ||
|
|
||
| final sections = registry.sections; | ||
|
|
||
| expect(sections, hasLength(2)); | ||
| expect(sections[0].key, 'alpha'); | ||
| expect(sections[1].key, 'beta'); | ||
| }); |
There was a problem hiding this comment.
This test asserts stable ordering for equal order values, but the current registry implementation uses List.sort, which is not guaranteed stable in Dart. As a result, this test can be flaky across SDK versions/platforms. Either implement a deterministic tie-break in the registry (e.g., registration sequence) or adjust the expectation to not rely on stability.
Add custom section registration API for team settings view
Problem
Host applications cannot inject custom form sections into the team settings view without overriding the entire view via
MagicStarter.view.register('teams.settings', ...). This forces apps to reimplement all built-in sections (General, Members, Invitations) just to add one project-specific card like billing or integrations.Context
use*()facade + manager registry pattern used throughout the pluginCode References
lib/src/ui/views/teams/magic_starter_team_settings_view.dart— currently hardcodes two section methods (_buildGeneralSection,_buildMembersSection) inbuild()lib/src/magic_starter_manager.dart:288-524— holds all extensibility points (view registry, theme, builders, etc.)lib/src/facades/magic_starter.dart— staticuse*()methods that delegate to manager fieldslib/src/ui/magic_starter_view_registry.dart— existingregister()/make()pattern for views, layouts, modalslib/src/models/magic_starter_team.dart— DTO withid,name,photoUrl,isPersonalTeamMagicStarterConfig.hasTeamFeatures()— must remain respectedExisting Patterns to Follow
The plugin already has builder/registry patterns on the manager:
headerBuilder: Widget Function(BuildContext, bool)?— custom headersidebarFooterBuilder: Widget Function(BuildContext)?— sidebar footersocialLoginBuilder— social login buttonsnavigationTheme/modalTheme— theme token objectsA section registry would follow the same manager-field + facade-method pattern, but with a keyed map instead of a single callback.
Expected API Shape (from user)
Out of Scope
hasTeamFeatures()Open Questions
MagicStarter.teamSettingsas a new namespace. The Developer should decide whether this warrants a new facade accessor (likeMagicStarter.view) or should live directly on the manager with aMagicStarter.useTeamSettingsSections()facade method — consistency with existing patterns should guide the decision.teamparameter type in the builder callback: the currentMagicStarterTeammodel is minimal (id, name, photoUrl, isPersonalTeam). Builders receive whatever the team resolver provides — no enrichment needed.Acceptance Criteria
registerSection(key:, order:, builder:)API exists and stores section definitions keyed by stringregisterSection(key: 'billing', order: 10, builder: ...)is called, then the section is stored and available for renderingordervalue (lower number = higher position among custom sections)removeSection(key)removes a previously registered sectionremoveSection('billing')is called, then the section no longer renders in the viewregisterSection(key: 'billing', ...)is called again with a different builder, then only the new builder renders (no duplicates)hasTeamFeatures()returns false, when the team settings route is accessed, then the feature gate behaves as before (sections are not rendered because the view/route is gated)Task: Add custom section registration API for team settings view