Skip to content

Add custom section registration API for team settings view#42

Open
anilcancakir wants to merge 4 commits intomainfrom
task/MGS-2
Open

Add custom section registration API for team settings view#42
anilcancakir wants to merge 4 commits intomainfrom
task/MGS-2

Conversation

@anilcancakir
Copy link
Copy Markdown
Contributor

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

  • Who: Host app developers extending Magic Starter's team management
  • Severity: Missing extensibility — common pattern needed for real-world team settings
  • Related: Follows the existing use*() facade + manager registry pattern used throughout the plugin

Code References

  • Team settings view: lib/src/ui/views/teams/magic_starter_team_settings_view.dart — currently hardcodes two section methods (_buildGeneralSection, _buildMembersSection) in build()
  • Manager (central registry): lib/src/magic_starter_manager.dart:288-524 — holds all extensibility points (view registry, theme, builders, etc.)
  • Facade: lib/src/facades/magic_starter.dart — static use*() methods that delegate to manager fields
  • View registry: lib/src/ui/magic_starter_view_registry.dart — existing register()/make() pattern for views, layouts, modals
  • Team model: lib/src/models/magic_starter_team.dart — DTO with id, name, photoUrl, isPersonalTeam
  • Feature gate: MagicStarterConfig.hasTeamFeatures() — must remain respected

Existing Patterns to Follow

The plugin already has builder/registry patterns on the manager:

  • headerBuilder: Widget Function(BuildContext, bool)? — custom header
  • sidebarFooterBuilder: Widget Function(BuildContext)? — sidebar footer
  • socialLoginBuilder — social login buttons
  • navigationTheme / modalTheme — theme token objects

A 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)

// Register in AppServiceProvider.boot()
MagicStarter.teamSettings.registerSection(
  key: 'billing',
  order: 10,
  builder: (context, team) => SectionCard(...),
);

// Remove if needed
MagicStarter.teamSettings.removeSection('billing');

Out of Scope

  • Custom sections for profile settings (separate feature)
  • Section-level permission/gate system beyond existing hasTeamFeatures()
  • Drag-and-drop section reordering in the UI
  • Built-in section reordering or removal by host apps

Open Questions

  • The user's proposed API uses MagicStarter.teamSettings as a new namespace. The Developer should decide whether this warrants a new facade accessor (like MagicStarter.view) or should live directly on the manager with a MagicStarter.useTeamSettingsSections() facade method — consistency with existing patterns should guide the decision.
  • The team parameter type in the builder callback: the current MagicStarterTeam model is minimal (id, name, photoUrl, isPersonalTeam). Builders receive whatever the team resolver provides — no enrichment needed.

Acceptance Criteria

  • Register section: registerSection(key:, order:, builder:) API exists and stores section definitions keyed by string
    • Given a host app's service provider boot method, when registerSection(key: 'billing', order: 10, builder: ...) is called, then the section is stored and available for rendering
  • Render custom sections: Custom sections appear in the team settings view after built-in sections
    • Given one or more custom sections are registered, when the team settings view renders, then custom sections appear below the built-in General and Members sections
  • Order sorting: Sections are sorted by order value (lower number = higher position among custom sections)
    • Given sections registered with order 20 and order 10, when the view renders, then the order-10 section appears above the order-20 section
  • Remove section: removeSection(key) removes a previously registered section
    • Given a section registered with key 'billing', when removeSection('billing') is called, then the section no longer renders in the view
  • Duplicate key replacement: Registering a section with an existing key replaces the previous one
    • Given a section registered with key 'billing', when registerSection(key: 'billing', ...) is called again with a different builder, then only the new builder renders (no duplicates)
  • Feature gate respected: Custom sections only render when team features are enabled
    • Given custom sections are registered but 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

Copilot AI review requested due to automatic review settings April 9, 2026 23:14
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 through MagicStarterManager) 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.

Comment on lines +72 to +78
/// 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));
}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Comment on lines +83 to +101
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');
});
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
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