Sub-Pages — Creating New Membership Components¶
Part of: Sub-Pages guide See also: Best Practices | Membership Tabs | Custom Implementation
This guide covers creating new membership components from scratch when no existing component matches your needs.
⚠️ IMPORTANT: Before creating a new component, verify that no existing component in
src/components/MemberOf/,src/components/Members/,src/components/MemberManagers/, orsrc/components/ManagedBy/matches your needs. See 06-membership-tabs.md for the list of existing components.
When to Create a New Component¶
Create a new component when:
A prompt specifies a component that doesn’t exist
No similar component exists that can be reused
The entity type or membership relationship is not covered by existing components
CRITICAL: Never Leave Functionality Incomplete¶
🛑 HARD RULE: When the prompt does not contain enough information to fully implement Add/Delete functionality, you MUST ASK for clarification. NEVER disable buttons or leave handlers empty without explicit user approval.
What “Complete” Means¶
A membership component is complete when it has:
Feature |
Implementation |
|---|---|
✅ Add button |
Enabled, opens a working modal |
✅ Add modal |
Fetches available items OR provides text input |
✅ Add action |
Calls the correct API mutation |
✅ Delete button |
Enabled when items are selected |
✅ Delete modal |
Shows confirmation with selected items |
✅ Delete action |
Calls the correct API mutation |
✅ Success/error alerts |
Displayed after operations |
What Is NOT Acceptable¶
// ❌ UNACCEPTABLE: Buttons disabled without asking
addButtonEnabled={false}
onAddButtonClick={() => {}} // Empty handler!
// ❌ UNACCEPTABLE: Creating read-only component when Add/Delete is expected
// Agent decided not to implement functionality instead of asking questions
What To Do Instead¶
If you don’t have enough information:
STOP before creating the component
ASK the user for the missing information (see questions below)
WAIT for the answer before implementing
If user explicitly wants read-only: get confirmation (“Should I disable Add/Delete for now?”)
Required Questions to Ask¶
Before creating any new membership component, you MUST ask the user for required information. The questions depend on whether you’re creating a Standard Membership Tab or an Independent Sub-Page.
How to Determine the Type¶
If the prompt mentions… |
It’s likely… |
|---|---|
|
Standard Membership Tab |
Uses |
Standard Membership Tab |
Uses entity-specific API like |
Independent Sub-Page |
Data from |
Independent Sub-Page |
Scenario A: Standard Membership Tab¶
Standard membership tabs use <entity>_add_member / <entity>_remove_member APIs with an entityType parameter.
Required Questions¶
# |
Question |
Purpose |
Example Answer |
|---|---|---|---|
1 |
Data source field |
Which |
|
2 |
API for available items (Add modal) |
What API lists available items to add? |
|
3 |
Item identifier field |
Which field from the API response identifies each item? |
|
4 |
Table column names |
What columns should display? |
|
5 |
Entity type for mutations |
What |
|
6 |
Direct/Indirect support |
Support membership direction toggle? |
No |
7 |
Add modal UI pattern |
DualListSelector (standard) or alternative? |
DualListSelector |
Example Question¶
“To create the ‘System accounts’ Members tab, I need:
Which field contains the data? (e.g.,
member_sysaccount)What API fetches available system accounts? (e.g.,
sysaccount_find)Which field identifies each item? (e.g.,
uid)What columns should display?
What
entityTypefor add/remove?Should the Direct/Indirect toggle be shown?
Use standard DualListSelector for Add modal?”
Scenario B: Independent Sub-Page¶
Independent sub-pages use entity-specific APIs (not generic _add_member/_remove_member).
Required Questions¶
# |
Question |
Purpose |
Example Answer |
|---|---|---|---|
1 |
Data source (API + field) |
Where does table data come from? |
|
2 |
API for available items |
What API lists available items? |
|
3 |
Item identifier field |
Which field identifies each item? |
|
4 |
Table column names |
What columns should display? |
|
5 |
API call for Add operation |
What method adds items? |
|
6 |
API call for Delete operation |
What method removes items? |
|
7 |
Add modal UI pattern |
DualListSelector or alternative? |
DualListSelector |
Example Question¶
“To create the ‘Privileges’ page for Roles, I need:
Where does the data come from?
What API fetches available privileges?
Which field identifies each privilege?
What columns should display?
What API adds privileges?
What API removes privileges?
Use standard DualListSelector for Add modal?”
If the User Doesn’t Know Technical Details¶
Guide them with simpler questions:
Instead of… |
Ask this… |
|---|---|
“What API call fetches items?” |
“What type of entity does this tab manage?” |
“What field identifies each item?” |
“How is each item uniquely identified?” (username, hostname) |
“What entityType for add/remove?” |
“What is the member attribute name?” (e.g., |
How to Find API Information¶
Check FreeIPA API docs: https://freeipa.readthedocs.io/en/latest/api/
Use browser DevTools on the old FreeIPA Web UI
Check similar implementations in
src/services/rpc*.ts
Default Assumptions (Ask for Confirmation)¶
If the user cannot provide specifics, propose defaults:
Standard Membership Tab Defaults¶
- Data source: member_<entityType> field
- API method: <entity>_find with no_members: true
- Item identifier: uid or cn (first element if array)
- Table columns: Single column with identifier
- Add/Remove: <parent>_add_member / <parent>_remove_member
- Direct/Indirect: Hidden (membershipDisabled={true})
- UI pattern: Standard DualListSelector
Independent Sub-Page Defaults¶
- Data source: Specific field from <parent>_show (may need all: true)
- API method: <related>_find with no_members: true
- Item identifier: cn (first element if array)
- Table columns: Single column with item name
- Add: <parent>_add_<relation>
- Remove: <parent>_remove_<relation>
- UI pattern: Standard DualListSelector
Component Creation Checklist¶
After gathering information, the component MUST include:
Required Feature |
Description |
|---|---|
Toolbar |
|
Table |
|
Pagination |
Bottom pagination component |
Add button |
Enabled, opens add modal |
Add modal |
|
Delete button |
Enabled when items selected |
Delete modal |
|
API mutations |
Appropriate |
Alerts |
Success/error alerts via |
Loading states |
Spinning indicator during API calls |
MembershipTable Type Registration¶
When creating membership tabs that use the MembershipTable component (src/components/tables/MembershipTable.tsx), you must ensure the entity types are properly registered.
Required Updates to MembershipTable.tsx¶
1. FromTypes Union¶
Add your new from value to the FromTypes union type:
type FromTypes =
| "active-users"
| "hbac-rules"
// ... existing types ...
| "your-new-type" // <-- Add your new type here
| "external";
2. EntryDataTypes Union (Object-based entities only)¶
If your membership data is an array of objects (e.g., User[], Host[], HBACServiceGroup[]), you must:
Import the interface from
globalDataTypes.tsAdd it to the
EntryDataTypesunion
import {
// ... existing imports ...
YourNewType, // <-- Add import
} from "src/utils/datatypes/globalDataTypes";
type EntryDataTypes =
| HBACRule
// ... existing types ...
| YourNewType // <-- Add to union
| string;
If your membership data is a string array (e.g., member_sysaccount: string[]), you do NOT need to update EntryDataTypes. Instead, add your from value to the STRING_ARRAY_TYPES constant:
const STRING_ARRAY_TYPES = ["external", "sysaccount", "idoverrideuser", "your-new-type"];
Why This Matters¶
Failing to register object-based entity types in EntryDataTypes will cause TypeScript errors like:
Type 'YourType[]' is not assignable to type 'EntryDataTypes[]'.
These errors may not appear immediately but can surface when other type definitions in the codebase change, making them difficult to trace back to the original omission.
Add Modal Pattern Selection¶
Default (use without asking): MemberOfAddModal + DualListSelectorGeneric
Alternative patterns (ASK USER FIRST):
ModalWithFormLayout+TextInput— For simple text entryModalWithFormLayout+IpaSelect— For single selection dropdownCustom modal — For complex scenarios
Reference implementations:
Standard pattern:
src/components/Members/MembersUsers.tsxTextInput pattern:
src/components/Members/MembersExternal.tsx
Summary¶
See 00-best-practices.md for the complete guide on golden rules, anti-patterns, and required practices when creating sub-pages.
Key reminders:
When in doubt, ASK — one extra question is better than an incomplete component
NEVER disable buttons or leave handlers empty without explicit user approval
ALWAYS run post-generation validation commands before committing