Skip to content

Commit

Permalink
Merge pull request #31 from shliachtx/github-actions
Browse files Browse the repository at this point in the history
Fix live updates
  • Loading branch information
shliachtx authored Jun 8, 2020
2 parents 68b1e0c + 50e701d commit 61d1ff4
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 83 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@

_No warranty is provided, express or implied_

[Install unlocked package](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008SZyYAAW) version 0.8.0
[Install unlocked package](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008SZzWAAW) version 0.10.0

## Release Notes
### 0.10.0
- Change live data updates to use PushTopic
### 0.8.0
- Add support for Change Data Capture.
### 0.7.0
Expand Down Expand Up @@ -41,9 +43,7 @@ To deploy authorize a dev hub in sfdx and run `$ sfdx force:org:create -f config
### [datatable](force-app/main/default/lwc/datatable)
Takes as input an sObject and an array of fields and populates a datatable with records from the database.

To enable Change Data Capture (live updates) follow instructions here: https://developer.salesforce.com/docs/atlas.en-us.change_data_capture.meta/change_data_capture/cdc_select_objects.htm

Note: Normal Change Data Capture limitations apply https://developer.salesforce.com/docs/atlas.en-us.change_data_capture.meta/change_data_capture/cdc_allocations.htm
Note: Streaming update support utilizes the PushTopic feature, which has a maximum of 50 PushTopic records per org. The datatable uses one for each object type that has live updates enabled. They can be deleted or deactivated if necessary - use `SELECT Id, IsActive FROM PushTopic WHERE Name LIKE 'easydt__%` to retrieve them via SOQL.

### [Custom Related List](force-app/main/default/lwc/relatedList)
Related list for use on lightning app and record pages. Choose object, fields, etc.
Expand Down
2 changes: 1 addition & 1 deletion force-app/main/default/lwc/datatable/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Name | Type |Read only | Required | Description | Default value
`enable-infinite-loading`|boolean|||automatically load more records when user reaches the end of the datatable|`false`
`records-per-batch`|integer|||number of records to load when the end of the datable is reached|`50`
`initial-records`|integer|||number of records to load initially|`this.recordsPerBatch`
`enableLiveUpdates`|boolean|||update records using Change Data Capture|`false`
`enableLiveUpdates`|boolean|||update records using PushTopic|`false`
`selected-rows`|array|✔||array of selected IDs from datatable
`query`|string|✔||generated query string used to retrieve data
`record-count`|integer|✔||total number of records returned by current query
Expand Down
136 changes: 66 additions & 70 deletions force-app/main/default/lwc/datatable/datatable.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { updateRecord } from "lightning/uiRecordApi";
import { refreshApex } from "@salesforce/apex";
import wireTableCache from "@salesforce/apex/DataTableService.wireTableCache";
import getTableCache from "@salesforce/apex/DataTableService.getTableCache";
import getPushTopic from "@salesforce/apex/DataTableService.getPushTopic";
import * as tableUtils from "c/tableServiceUtils";
import * as datatableUtils from "./datatableUtils";
import {
Expand All @@ -28,7 +29,7 @@ export default class Datatable extends LightningElement {
* See README.md
***/
// _wiredResults;
lastEventId = 0;
lastEventId = -1;
subscription;
wiredResults;
_sObject = "";
Expand Down Expand Up @@ -59,7 +60,15 @@ export default class Datatable extends LightningElement {
@api recordsPerBatch = 50;
@api editable;
@api showSoql;
@api enableLiveUpdates;
@api
get enableLiveUpdates() {
return this._enableLiveUpdates;
}
set enableLiveUpdates(value) {
this._enableLiveUpdates = value;
// eslint-disable-next-line no-self-assign
this.sObject = this.sObject;
}

get sortedByFormatted() {
let name = this._sortedBy;
Expand Down Expand Up @@ -120,6 +129,17 @@ export default class Datatable extends LightningElement {
}
set sObject(value) {
this._sObject = value;
if (this.enableLiveUpdates) {
getPushTopic({ sObjectApiName: value })
.then( (channelName) => {
this.channelName = channelName
if (true) { //isEmpEnabled
return this.pushTopicSubscribe(channelName)
}
return undefined;
});
}

this.tableRequest = "reset";
}
@api // filter;
Expand Down Expand Up @@ -199,18 +219,6 @@ export default class Datatable extends LightningElement {
wiredObjectInfo({ error, data }) {
if (data) {
this.objectInfo = data;

if (isEmpEnabled && this.enableLiveUpdates) {
let channelName = `/data/${this.sObject}`;
if (this.objectInfo.custom) {
channelName =
channelName.substring(0, channelName.length - 1) + "ChangeEvent";
} else {
channelName = channelName + "ChangeEvent";
}

this.changeDataCaptureSubscribe(channelName);
}
} else if (error) {
this.error(error.statusText + ": " + error.body.message);
}
Expand Down Expand Up @@ -327,44 +335,41 @@ export default class Datatable extends LightningElement {
}

get where() {
let filter = this.filter;
let search;
if (this.search) {
let searchTerm = this.search.replace("'", "\\'");
search = this.fields
.filter((field) => {
if (Object.prototype.hasOwnProperty.call(field, "searchable")) {
return field.searchable;
}
if (!this.objectInfo || !this.objectInfo.fields[field.fieldName]) {
return false;
}
let fieldType = this.objectInfo.fields[field.fieldName].dataType;
return (
fieldType === "String" ||
fieldType === "Email" ||
fieldType === "Phone"
);
})
.map((field) => {
return field.fieldName + " LIKE '%" + searchTerm + "%'";
})
.join(" OR ");
if (search) {
search = "(" + search + ")";
}
}
if (filter && search) {
filter += " AND " + search;
} else if (search) {
filter = search;
}
if (filter) {
return " WHERE " + filter;
let filterItems = [this.filter, this.searchQuery].filter(f => f);

if (filterItems.length) {
return " WHERE " + filterItems.join(' AND ');
}
return "";
}

get searchQuery() {
let searchTerm = this.search.replace("'", "\\'");
let search = this.fields
.filter((field) => {
if (Object.prototype.hasOwnProperty.call(field, "searchable")) {
return field.searchable;
}
if (!this.objectInfo || !this.objectInfo.fields[field.fieldName]) {
return false;
}
let fieldType = this.objectInfo.fields[field.fieldName].dataType;
return (
fieldType === "String" ||
fieldType === "Email" ||
fieldType === "Phone"
);
})
.map((field) => {
return field.fieldName + " LIKE '%" + searchTerm + "%'";
})
.join(" OR ");
if (search) {
search = "(" + search + ")";
}
return search;
}

get orderBy() {
if (!this.sortedBy) this.error("Sort field is required");
let sortedDirection =
Expand Down Expand Up @@ -479,7 +484,7 @@ export default class Datatable extends LightningElement {

getRowValue(recordId) {
let filter =
this.where + (this.filter ? " AND " : " WHERE ") + `Id='${recordId}'`;
this.where + (this.where ? " AND " : " WHERE ") + `Id='${recordId}'`;
let query = this.buildQuery(
this.fields,
this.sObject,
Expand Down Expand Up @@ -537,44 +542,35 @@ export default class Datatable extends LightningElement {
}
}

changeDataCaptureSubscribe(channelName) {
pushTopicSubscribe(channelName) {
const messageCallback = (response) => {
console.log("New message received:", JSON.stringify(response));
console.log(JSON.parse(JSON.stringify(response)));
const payload = response.data.payload;
const eventHeader = payload.ChangeEventHeader;
if (
this.lastEventId < response.data.event.replayId &&
eventHeader.entityName === this.sObject
) {
switch (eventHeader.changeType) {
case "CREATE":
eventHeader.recordIds.map((recordId) =>
this.addRow(recordId, payload)
);
const event = response.data.event;
const recordId = response.data.sobject.Id;
if (this.lastEventId < event.replayId) {
switch (event.type) {
case "created":
this.addRow(recordId);
break;
case "UPDATE":
eventHeader.recordIds.map((recordId) =>
this.updateRow(recordId, payload)
);
case "updated":
this.updateRow(recordId);
break;
case "DELETE":
eventHeader.recordIds.map((recordId) => this.removeRow(recordId));
case "deleted":
this.removeRow(recordId);
break;
default:
break;
}
}
};

subscribe(channelName, -1, messageCallback).then((response) => {
return subscribe(channelName, -1, messageCallback).then((response) => {
console.log(
"Successfully subscribed to : ",
JSON.stringify(response.channel)
);
if (this.subscription) {
unsubscribe(this.subscription, (resp) => {
console.log("unsubscribe() response: ", JSON.stringify(resp));
console.log(JSON.parse(JSON.stringify(resp)));
});
}
Expand Down
12 changes: 6 additions & 6 deletions force-app/main/default/lwc/relatedList/relatedList.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,17 @@ export default class RelatedList extends LightningElement {
}

get parentRecordId() {
if (this.parentRecordField && this.parentRecord && this.parentRecord.data)
if (!this.parentRecordField) {
return undefined;
} else if (this.parentRecord && this.parentRecord.data) {
return getFieldValue(this.parentRecord.data, this.fullParentRecordField);
}
return "";
}

get parentRelationship() {
if (this.parentRecordField && this.childRecordField) {
if (this.parentRecordId) {
return " " + this.childRecordField + " = '" + this.parentRecordId + "'";
}
return " " + this.childRecordField + " = ''"; // return empty string so the query returns no results
if (this.childRecordField && typeof this.parentRecordId !== undefined) {
return `${this.childRecordField}='${this.parentRecordId}'`;
}
return "";
}
Expand Down
29 changes: 29 additions & 0 deletions force-app/main/lwc-utils/classes/DataTableService.cls
Original file line number Diff line number Diff line change
Expand Up @@ -227,4 +227,33 @@ public with sharing class DataTableService {
return tableColumns;
}

@AuraEnabled
public static String getPushTopic(String sObjectApiName) {
String name = 'easydt__'+sObjectApiName;
String query = 'SELECT Id FROM ' + sObjectApiName;
PushTopic pt;
PushTopic[] pushTopics = [SELECT Id,Name,IsActive FROM PushTopic WHERE Name=:name LIMIT 1];
if (pushTopics.size() > 0) {
pt = pushTopics[0];

if (!pt.IsActive) {
pt.IsActive = true;
update pt;
}
} else {
pt = new PushTopic();
pt.Name=name;
pt.ApiVersion=48;
pt.NotifyForOperationCreate=true;
pt.NotifyForOperationUpdate=true;
pt.NotifyForOperationDelete=true;
pt.NotifyForFields='All';
pt.Query=query;

insert pt;
}

return '/topic/' + pt.Name;
}

}
6 changes: 4 additions & 2 deletions sfdx-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"path": "force-app",
"default": true,
"package": "lwc",
"versionNumber": "0.6.0.NEXT"
"versionNumber": "0.9.0.NEXT"
}
],
"namespace": "easydt",
Expand All @@ -23,6 +23,8 @@
"[email protected]": "04t6g000004O28tAAC",
"[email protected]": "04t6g000004OWs4AAG",
"[email protected]": "04t6g000008fW6kAAE",
"[email protected]": "04t6g000008SZyYAAW"
"[email protected]": "04t6g000008SZyYAAW",
"[email protected]": "04t6g000008SZzRAAW",
"[email protected]": "04t6g000008SZzWAAW"
}
}

0 comments on commit 61d1ff4

Please sign in to comment.