220 lines
6.5 KiB
Markdown
220 lines
6.5 KiB
Markdown
# Related Lists and Lookup Fields Implementation
|
|
|
|
This document describes the implementation of related lists and improved relationship field handling in the application.
|
|
|
|
## Features Implemented
|
|
|
|
### 1. Related Lists Component (`/frontend/components/RelatedList.vue`)
|
|
|
|
A reusable component that displays related records for a parent entity in a table format.
|
|
|
|
**Features:**
|
|
- Displays related records in a formatted table
|
|
- Shows configurable fields for each related record
|
|
- Supports navigation to related record detail pages
|
|
- Allows creating new related records
|
|
- Handles loading and error states
|
|
- Empty state with call-to-action button
|
|
- Automatically fetches related records or uses provided data
|
|
|
|
**Usage Example:**
|
|
```vue
|
|
<RelatedList
|
|
:config="{
|
|
title: 'Domains',
|
|
relationName: 'domains',
|
|
objectApiName: 'domains',
|
|
fields: [...],
|
|
canCreate: true
|
|
}"
|
|
:parent-id="tenantId"
|
|
:related-records="tenant.domains"
|
|
@navigate="handleNavigate"
|
|
@create="handleCreate"
|
|
/>
|
|
```
|
|
|
|
### 2. Lookup Field Component (`/frontend/components/fields/LookupField.vue`)
|
|
|
|
A searchable dropdown component for selecting related records (belongs-to relationships).
|
|
|
|
**Features:**
|
|
- Searchable combobox for finding records
|
|
- Fetches available records from API
|
|
- Displays meaningful field names instead of UUIDs
|
|
- Clear button to remove selection
|
|
- Configurable relation object and display field
|
|
- Loading states
|
|
|
|
**Usage:**
|
|
```vue
|
|
<LookupField
|
|
:field="{
|
|
type: FieldType.BELONGS_TO,
|
|
relationObject: 'tenants',
|
|
relationDisplayField: 'name',
|
|
...
|
|
}"
|
|
v-model="domainData.tenantId"
|
|
base-url="/api/central"
|
|
/>
|
|
```
|
|
|
|
### 3. Enhanced Field Renderer (`/frontend/components/fields/FieldRenderer.vue`)
|
|
|
|
Updated to handle relationship fields intelligently.
|
|
|
|
**New Features:**
|
|
- Detects BELONGS_TO field type
|
|
- Fetches related record for display in detail/list views
|
|
- Shows meaningful name instead of UUID
|
|
- Uses LookupField component for editing
|
|
- Automatic loading of related record data
|
|
|
|
**Behavior:**
|
|
- **Detail/List View:** Fetches and displays related record name
|
|
- **Edit View:** Renders LookupField for selection
|
|
- Falls back to UUID if related record can't be fetched
|
|
|
|
### 4. Enhanced Detail View (`/frontend/components/views/DetailView.vue`)
|
|
|
|
Added support for displaying related lists below the main record details.
|
|
|
|
**New Features:**
|
|
- `relatedLists` configuration support
|
|
- Emits `navigate` and `createRelated` events
|
|
- Passes related records data to RelatedList components
|
|
- Automatically displays all configured related lists
|
|
|
|
### 5. Type Definitions (`/frontend/types/field-types.ts`)
|
|
|
|
Added new types for related list configuration:
|
|
|
|
```typescript
|
|
export interface RelatedListConfig {
|
|
title: string;
|
|
relationName: string; // Property name on parent object
|
|
objectApiName: string; // API endpoint name
|
|
fields: FieldConfig[]; // Fields to display in list
|
|
canCreate?: boolean;
|
|
createRoute?: string;
|
|
}
|
|
|
|
export interface DetailViewConfig extends ViewConfig {
|
|
mode: ViewMode.DETAIL;
|
|
sections?: FieldSection[];
|
|
actions?: ViewAction[];
|
|
relatedLists?: RelatedListConfig[]; // NEW
|
|
}
|
|
```
|
|
|
|
### 6. Backend Support (`/backend/src/tenant/central-admin.controller.ts`)
|
|
|
|
Added filtering support for fetching related records.
|
|
|
|
**Enhancement:**
|
|
```typescript
|
|
@Get('domains')
|
|
async getDomains(
|
|
@Req() req: any,
|
|
@Query('parentId') parentId?: string,
|
|
@Query('tenantId') tenantId?: string,
|
|
) {
|
|
// ...
|
|
if (parentId || tenantId) {
|
|
query = query.where('tenantId', parentId || tenantId);
|
|
}
|
|
return query;
|
|
}
|
|
```
|
|
|
|
### 7. Central Entities Configuration (`/frontend/composables/useCentralEntities.ts`)
|
|
|
|
Added related list configurations to tenant detail view:
|
|
|
|
```typescript
|
|
export const tenantDetailConfig: DetailViewConfig = {
|
|
// ... existing config
|
|
relatedLists: [
|
|
{
|
|
title: 'Domains',
|
|
relationName: 'domains',
|
|
objectApiName: 'domains',
|
|
fields: [
|
|
{ id: 'domain', apiName: 'domain', label: 'Domain', type: FieldType.TEXT },
|
|
{ id: 'isPrimary', apiName: 'isPrimary', label: 'Primary', type: FieldType.BOOLEAN },
|
|
{ id: 'createdAt', apiName: 'createdAt', label: 'Created', type: FieldType.DATETIME },
|
|
],
|
|
canCreate: true,
|
|
},
|
|
],
|
|
}
|
|
```
|
|
|
|
Updated domain field configuration to use lookup:
|
|
|
|
```typescript
|
|
{
|
|
id: 'tenantId',
|
|
apiName: 'tenantId',
|
|
label: 'Tenant',
|
|
type: FieldType.BELONGS_TO, // Changed from TEXT
|
|
relationObject: 'tenants',
|
|
relationDisplayField: 'name',
|
|
// ...
|
|
}
|
|
```
|
|
|
|
## User Experience Improvements
|
|
|
|
### Before:
|
|
- **Relationship Fields:** Displayed raw UUIDs everywhere
|
|
- **Editing Relationships:** Had to manually enter or paste UUIDs
|
|
- **Related Records:** No way to see child records from parent detail page
|
|
- **Navigation:** Had to manually navigate to related record lists
|
|
|
|
### After:
|
|
- **Relationship Fields:** Show meaningful names (e.g., "Acme Corp" instead of "abc-123-def")
|
|
- **Editing Relationships:** Searchable dropdown with all available options
|
|
- **Related Records:** Automatically displayed in related lists on detail pages
|
|
- **Navigation:** One-click navigation to related records; create button with parent context pre-filled
|
|
|
|
## Example: Tenant Detail View
|
|
|
|
When viewing a tenant, users now see:
|
|
|
|
1. **Main tenant information** (name, slug, status, database config)
|
|
2. **Related Lists section** below main details:
|
|
- **Domains list** showing all domains for this tenant
|
|
- Each domain row displays: domain name, isPrimary flag, created date
|
|
- "New" button to create domain with tenantId pre-filled
|
|
- Click any domain to navigate to its detail page
|
|
|
|
## Example: Creating a Domain
|
|
|
|
When creating/editing a domain:
|
|
|
|
1. **Tenant field** shows a searchable dropdown instead of text input
|
|
2. Type to search available tenants by name
|
|
3. Select from list - shows "Acme Corp" not "uuid-123"
|
|
4. Selected tenant's name is displayed
|
|
5. Can clear selection with X button
|
|
|
|
## Technical Notes
|
|
|
|
- All API calls use the centralized `$api` helper from `useNuxtApp()`
|
|
- Type casting via `unknown` to handle NuxtApp type issues
|
|
- Filter functions use TypeScript type predicates for proper type narrowing
|
|
- Related records can be passed in (if already fetched with parent) or fetched separately
|
|
- Backend supports both `parentId` and specific relationship field names (e.g., `tenantId`)
|
|
|
|
## Future Enhancements
|
|
|
|
Potential additions:
|
|
- Inline editing within related lists
|
|
- Pagination for large related lists
|
|
- Sorting and filtering within related lists
|
|
- Bulk operations on related records
|
|
- Many-to-many relationship support
|
|
- Has-many relationship support with junction tables
|