WIP - display related lists
This commit is contained in:
@@ -135,7 +135,7 @@ export class DynamicModelFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetTable = this.getTableName(relation.targetObjectApiName);
|
const targetTable = DynamicModelFactory.getTableName(relation.targetObjectApiName);
|
||||||
|
|
||||||
if (relation.type === 'belongsTo') {
|
if (relation.type === 'belongsTo') {
|
||||||
mappings[relation.name] = {
|
mappings[relation.name] = {
|
||||||
|
|||||||
@@ -643,6 +643,7 @@ export class ObjectService {
|
|||||||
relationName: string;
|
relationName: string;
|
||||||
objectApiName: string;
|
objectApiName: string;
|
||||||
lookupFieldApiName: string;
|
lookupFieldApiName: string;
|
||||||
|
parentObjectApiName: string;
|
||||||
fields: any[];
|
fields: any[];
|
||||||
}>> {
|
}>> {
|
||||||
const knex = await this.tenantDbService.getTenantKnexById(tenantId);
|
const knex = await this.tenantDbService.getTenantKnexById(tenantId);
|
||||||
@@ -703,6 +704,7 @@ export class ObjectService {
|
|||||||
relationName,
|
relationName,
|
||||||
objectApiName: lookup.childApiName,
|
objectApiName: lookup.childApiName,
|
||||||
lookupFieldApiName: lookup.fieldApiName,
|
lookupFieldApiName: lookup.fieldApiName,
|
||||||
|
parentObjectApiName: objectApiName,
|
||||||
fields: fieldsByObject.get(lookup.objectDefinitionId) || [],
|
fields: fieldsByObject.get(lookup.objectDefinitionId) || [],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ interface RelatedListConfig {
|
|||||||
relationName: string // e.g., 'domains', 'users'
|
relationName: string // e.g., 'domains', 'users'
|
||||||
objectApiName: string // e.g., 'domains', 'users'
|
objectApiName: string // e.g., 'domains', 'users'
|
||||||
fields: FieldConfig[] // Fields to display in the list
|
fields: FieldConfig[] // Fields to display in the list
|
||||||
|
lookupFieldApiName?: string // Used to filter by parentId when fetching
|
||||||
|
parentObjectApiName?: string // Parent object API name, used to derive lookup field if missing
|
||||||
canCreate?: boolean
|
canCreate?: boolean
|
||||||
createRoute?: string // Route to create new related record
|
createRoute?: string // Route to create new related record
|
||||||
}
|
}
|
||||||
@@ -19,11 +21,11 @@ interface Props {
|
|||||||
config: RelatedListConfig
|
config: RelatedListConfig
|
||||||
parentId: string
|
parentId: string
|
||||||
relatedRecords?: any[] // Can be passed in if already fetched
|
relatedRecords?: any[] // Can be passed in if already fetched
|
||||||
baseUrl?: string // Base API URL, defaults to '/central'
|
baseUrl?: string // Base API URL, defaults to runtime objects
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
baseUrl: '/central',
|
baseUrl: '/runtime/objects',
|
||||||
relatedRecords: undefined,
|
relatedRecords: undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -53,14 +55,48 @@ const fetchRelatedRecords = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Replace :parentId placeholder in the API path
|
// Replace :parentId placeholder in the API path
|
||||||
let apiPath = props.config.objectApiName.replace(':parentId', props.parentId)
|
const sanitizedBase = props.baseUrl.replace(/\/$/, '')
|
||||||
|
let apiPath = props.config.objectApiName.replace(':parentId', props.parentId).replace(/^\/+/, '')
|
||||||
|
const isRuntimeObjects = sanitizedBase.endsWith('/runtime/objects')
|
||||||
|
|
||||||
const response = await api.get(`${props.baseUrl}/${apiPath}`, {
|
// Default runtime object routes expect /:objectApiName/records
|
||||||
|
if (isRuntimeObjects && !apiPath.includes('/')) {
|
||||||
|
apiPath = `${apiPath}/records`
|
||||||
|
}
|
||||||
|
|
||||||
|
const findLookupKey = () => {
|
||||||
|
if (props.config.lookupFieldApiName) return props.config.lookupFieldApiName
|
||||||
|
|
||||||
|
const parentName = props.config.parentObjectApiName?.toLowerCase()
|
||||||
|
const fields = props.config.fields || []
|
||||||
|
|
||||||
|
const parentMatch = fields.find(field => {
|
||||||
|
const relation = (field as any).relationObject || (field as any).referenceObject
|
||||||
|
return relation && parentName && relation.toLowerCase() === parentName
|
||||||
|
})
|
||||||
|
if (parentMatch?.apiName) return parentMatch.apiName
|
||||||
|
|
||||||
|
const lookupMatch = fields.find(
|
||||||
|
field => (field.type || '').toString().toLowerCase() === 'lookup'
|
||||||
|
)
|
||||||
|
if (lookupMatch?.apiName) return lookupMatch.apiName
|
||||||
|
|
||||||
|
const idMatch = fields.find(field =>
|
||||||
|
field.apiName?.toLowerCase().endsWith('id')
|
||||||
|
)
|
||||||
|
if (idMatch?.apiName) return idMatch.apiName
|
||||||
|
|
||||||
|
return 'parentId'
|
||||||
|
}
|
||||||
|
|
||||||
|
const lookupKey = findLookupKey()
|
||||||
|
|
||||||
|
const response = await api.get(`${sanitizedBase}/${apiPath}`, {
|
||||||
params: {
|
params: {
|
||||||
parentId: props.parentId,
|
[lookupKey]: props.parentId,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
records.value = response || []
|
records.value = response?.data || response || []
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error('Error fetching related records:', err)
|
console.error('Error fetching related records:', err)
|
||||||
error.value = err.message || 'Failed to fetch related records'
|
error.value = err.message || 'Failed to fetch related records'
|
||||||
|
|||||||
@@ -247,6 +247,7 @@ const visibleRelatedLists = computed<RelatedListConfig[]>(() => {
|
|||||||
:config="relatedList"
|
:config="relatedList"
|
||||||
:parent-id="data.id"
|
:parent-id="data.id"
|
||||||
:related-records="data[relatedList.relationName]"
|
:related-records="data[relatedList.relationName]"
|
||||||
|
:base-url="baseUrl"
|
||||||
@navigate="(objectApiName, recordId) => emit('navigate', objectApiName, recordId)"
|
@navigate="(objectApiName, recordId) => emit('navigate', objectApiName, recordId)"
|
||||||
@create="(objectApiName, parentId) => emit('createRelated', objectApiName, parentId)"
|
@create="(objectApiName, parentId) => emit('createRelated', objectApiName, parentId)"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ onMounted(async () => {
|
|||||||
:config="domainDetailConfig"
|
:config="domainDetailConfig"
|
||||||
:data="currentRecord"
|
:data="currentRecord"
|
||||||
:loading="dataLoading"
|
:loading="dataLoading"
|
||||||
|
base-url="/central"
|
||||||
@edit="handleEdit"
|
@edit="handleEdit"
|
||||||
@delete="() => handleDelete([currentRecord])"
|
@delete="() => handleDelete([currentRecord])"
|
||||||
@back="handleBack"
|
@back="handleBack"
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ onMounted(async () => {
|
|||||||
:config="tenantDetailConfig"
|
:config="tenantDetailConfig"
|
||||||
:data="currentRecord"
|
:data="currentRecord"
|
||||||
:loading="dataLoading"
|
:loading="dataLoading"
|
||||||
|
base-url="/central"
|
||||||
@edit="handleEdit"
|
@edit="handleEdit"
|
||||||
@delete="() => handleDelete([currentRecord])"
|
@delete="() => handleDelete([currentRecord])"
|
||||||
@back="handleBack"
|
@back="handleBack"
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ onMounted(async () => {
|
|||||||
:config="centralUserDetailConfig"
|
:config="centralUserDetailConfig"
|
||||||
:data="currentRecord"
|
:data="currentRecord"
|
||||||
:loading="dataLoading"
|
:loading="dataLoading"
|
||||||
|
base-url="/central"
|
||||||
@edit="handleEdit"
|
@edit="handleEdit"
|
||||||
@delete="() => handleDelete([currentRecord])"
|
@delete="() => handleDelete([currentRecord])"
|
||||||
@back="handleBack"
|
@back="handleBack"
|
||||||
|
|||||||
@@ -123,6 +123,8 @@ export interface RelatedListConfig {
|
|||||||
relationName: string;
|
relationName: string;
|
||||||
objectApiName: string;
|
objectApiName: string;
|
||||||
fields: FieldConfig[];
|
fields: FieldConfig[];
|
||||||
|
lookupFieldApiName?: string;
|
||||||
|
parentObjectApiName?: string;
|
||||||
canCreate?: boolean;
|
canCreate?: boolean;
|
||||||
createRoute?: string;
|
createRoute?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user