Skip to content

Commit 135a61b

Browse files
authored
New Related List custom component (#2119)
1 parent b1a8622 commit 135a61b

File tree

6 files changed

+606
-0
lines changed

6 files changed

+606
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
public with sharing class TAG_RelatedListController {
2+
/**
3+
* @description: Returns a list of records
4+
* @return List<sObject>
5+
**/
6+
@AuraEnabled(cacheable=true)
7+
public static List<sObject> getCRMRelatedList(
8+
String parentId,
9+
String objectApiName,
10+
String relationField,
11+
String parentRelationField,
12+
String parentObjectApiName,
13+
String dateField,
14+
String filterConditions,
15+
String orderConditions
16+
) {
17+
Set<String> parentRelationIds = getParentRelation(parentId, parentRelationField, parentObjectApiName);
18+
if (parentRelationIds.isEmpty()) {
19+
return new List<SObject>();
20+
}
21+
22+
String query = 'SELECT Id' + (String.isBlank(dateField) ? '' : ', ' + dateField);
23+
query += ' FROM ' + objectApiName + ' WHERE ';
24+
query += String.isNotBlank(filterConditions) ? filterConditions.trim() + ' AND ' : '';
25+
// query += relationField + ' IN (SELECT ' + parentRelationField + ' FROM ' + parentObjectApiName + ' WHERE Id = \'' + parentId + '\')';
26+
query += relationField + ' IN :parentRelationIds ';
27+
query += 'ORDER BY ' + (orderConditions != null ? orderConditions : 'ID DESC');
28+
29+
List<sObject> returnList = Database.query(query);
30+
return returnList;
31+
}
32+
33+
@AuraEnabled
34+
public static List<sObject> getRelatedList(
35+
List<String> fieldNames,
36+
String parentId,
37+
String objectApiName,
38+
String relationField,
39+
String parentRelationField,
40+
String parentObjectApiName,
41+
String filterConditions
42+
) {
43+
Set<String> parentRelationIds = getParentRelation(parentId, parentRelationField, parentObjectApiName);
44+
String query = 'SELECT ';
45+
46+
//Appending fields to query string
47+
for (String field : fieldNames) {
48+
query += field + ', ';
49+
}
50+
51+
query = query.removeEndIgnoreCase(', ') + ' FROM ' + objectApiName + ' WHERE ';
52+
query += String.isNotBlank(filterConditions) ? filterConditions.trim() + ' AND ' : '';
53+
// query += relationField + ' IN (SELECT ' + parentRelationField + ' FROM ' + parentObjectApiName + ' WHERE Id = \'' + parentId + '\')';
54+
query += relationField + ' IN :parentRelationIds ORDER BY ID DESC';
55+
56+
List<sObject> returnList = Database.query(query);
57+
return returnList;
58+
}
59+
60+
/**
61+
* @description: Returns a set of Strings to be used in getRelatedList
62+
* @return Set<String>
63+
*/
64+
private static Set<String> getParentRelation(
65+
String parentId,
66+
String parentRelationField,
67+
String parentObjectApiName
68+
) {
69+
Set<String> parentRelationIds = new Set<String>();
70+
String query = 'SELECT ' + parentRelationField + ' FROM ' + parentObjectApiName + ' WHERE Id = :parentId';
71+
72+
String relationId;
73+
for (SObject sObj : Database.query(query)) {
74+
relationId = getParentRelationId(sObj, parentRelationField);
75+
if (relationId != null)
76+
parentrelationIds.add(relationId);
77+
}
78+
79+
return parentRelationIds;
80+
}
81+
82+
/**
83+
* @description: Get the parent relation Id from sObject. Will recursively walk through the field hierarchy
84+
* @return String
85+
*/
86+
private static String getParentRelationId(Sobject obj, String parentRelationField) {
87+
List<String> relationHierarchy = parentRelationField.split('\\.');
88+
String fieldApiName = relationHierarchy.remove(0);
89+
90+
if (relationHierarchy.isEmpty()) {
91+
return (String) obj.get(fieldApiName);
92+
} else {
93+
return getParentRelationId(obj.getSObject(fieldApiName), String.join(relationHierarchy, '.'));
94+
}
95+
96+
}
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>62.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
.headerContainer {
2+
display: flex;
3+
align-items: center;
4+
justify-content: space-between;
5+
padding: 0.25rem 0.5rem;
6+
}
7+
8+
.headerLeft {
9+
display: flex;
10+
align-items: center;
11+
cursor: pointer;
12+
}
13+
14+
.headerIcon {
15+
width: 1.5rem;
16+
height: 1.5rem;
17+
}
18+
19+
.headerTitle {
20+
margin: 0 0.5rem;
21+
line-height: 1.5rem;
22+
}
23+
24+
.headerToggle {
25+
margin-left: 0.5rem;
26+
line-height: 1.5rem;
27+
}
28+
29+
.newRecordButton {
30+
align-self: center;
31+
height: 2rem;
32+
padding: 0 0.5rem;
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<template>
2+
<article class="slds-card">
3+
<!-- HEADER WITH TOGGLE AND "NEW RECORD" BUTTON -->
4+
<div class="headerContainer" style={headerBackground}>
5+
<!-- Left Group: Icon, Title, Toggle Icon -->
6+
<div class="headerLeft" onclick={toggleAccordion}>
7+
<template if:true={icon}>
8+
<lightning-icon icon-name={icon} size="small" class="headerIcon slds-m-right_x-small"></lightning-icon>
9+
</template>
10+
<h1 class="headerTitle slds-text-heading_small">{cardTitle}</h1>
11+
<span class="headerToggle">{toggleIcon}</span>
12+
</div>
13+
<!-- Right Group: New Record Button -->
14+
<template if:true={showNewRecordButton}>
15+
<lightning-button
16+
label={newRecordButtonLabel}
17+
variant="brand"
18+
onclick={handleNewRecord}
19+
class="newRecordButton slds-m-left_small">
20+
</lightning-button>
21+
</template>
22+
</div>
23+
24+
<!-- TABLE RENDERED BASED ON EXPANSION STATE -->
25+
<template if:true={showRecords}>
26+
<div style="overflow:auto; max-height: {maxHeight}em;">
27+
<table class="slds-table slds-table_cell-buffer slds-table_bordered slds-max-medium-table_stacked-horizontal" style="table-layout: auto;">
28+
<thead>
29+
<tr class="slds-line-height_reset">
30+
<template for:each={fieldLabels} for:item="label">
31+
<th key={label.value} scope="col" style={label.headerStyle}>
32+
<div style="display: flex; align-items: center; height: 100%; font-size: 0.75rem; white-space: nowrap;" title={label.value}>
33+
{label.value}
34+
</div>
35+
</th>
36+
</template>
37+
</tr>
38+
</thead>
39+
<tbody>
40+
<template for:each={displayedRecords} for:item="record" for:index="rowIndex">
41+
<!-- For clickable rows, added mouse event handlers for popover -->
42+
<template if:true={clickableRows}>
43+
<tr key={record.Id} data-record-id={record.Id} data-value={rowIndex} class="slds-hint-parent" onclick={handleRowClick} style="cursor: pointer"
44+
onmouseenter={handleMouseEnter} onmouseleave={handleMouseLeave}>
45+
<template for:each={record.recordFields} for:item="field">
46+
<td key={field.label}>
47+
<div class="slds-truncate slds-cell-wrap">{field.value}</div>
48+
</td>
49+
</template>
50+
</tr>
51+
</template>
52+
<!-- For non-clickable rows, also added mouse event handlers for popover -->
53+
<template if:false={clickableRows}>
54+
<tr key={record.Id} data-record-id={record.Id} data-value={rowIndex} class="slds-hint-parent"
55+
onmouseenter={handleMouseEnter} onmouseleave={handleMouseLeave}>
56+
<template for:each={record.recordFields} for:item="field">
57+
<td key={field.label}>
58+
<div class="slds-truncate slds-cell-wrap">{field.value}</div>
59+
</td>
60+
</template>
61+
</tr>
62+
</template>
63+
</template>
64+
</tbody>
65+
</table>
66+
</div>
67+
</template>
68+
69+
<!-- Popover Template for additional record details -->
70+
<template if:true={showPopover}>
71+
<div class="slds-popover slds-nubbin_top" style={popoverStyle} onmouseleave={handleMouseLeave}>
72+
<div class="slds-popover__body">
73+
<template for:each={popoverFieldValues} for:item="fieldObj">
74+
<p key={fieldObj.apiName}>
75+
<strong>{fieldObj.apiName}:</strong> {fieldObj.value}
76+
</p>
77+
</template>
78+
</div>
79+
</div>
80+
</template>
81+
</article>
82+
</template>

0 commit comments

Comments
 (0)