Complete template script example
const { DataRecord, DataModelEntity, Relation } = sirenapi;
const { EuiText, EuiTextColor, EuiIcon } = Eui;
const loading = 'Loading...';
function getInitialData() {
return ({
companyName: loading,
raisedAmount: loading
})
}
/**
* Common function for data fetching and calculations.
*
* While the "enrich" operation is in progress, "render" is called
* periodically to render the data with its most recent state.
*
* The 'input' object has the following properties:
* - "source" is the raw source object representing the record data
*
* - "record" is a "DataRecord" instance for the displayed record
*
* - "dataModelEntity" is a "DataModelEntity" instance for the data model
* entity that prompted the record display
*
* - "computedData" is the object used to store fetched data and make it
* available to the "render" function
*
* - "cancelPromise" is a promise that gets rejected in case of
* cancellation (for example, the user changes page or closes the
* Record Viewer)
*/
async function enrichRecordData({
source, record, dataModelEntity, cancelPromise, computedData
}) {
// It's best to bail out early if the script is used with an
// unsupported data model entity.
const rootEntity = await dataModelEntity.getRoot();
if (await rootEntity.getLabel() !== 'Companies') {
throw new Error('This script only works for Company records');
}
// We can ask for a label straight away with the "getLabel()" method.
const companyName = await record.getLabel();
// Store the fetched data using "computedData" object. An internal
// interval will be using updated computed data to refresh the view.
computedData.companyName = companyName;
// Raw field values are immediately available in the "source" parameter.
computedData.location = source.countrycode ?
`${source.city} (${source.countrycode})` : source.city;
// Skip complex calculations if their results have been cached by Investigate
if (computedData.raisedAmount === loading) {
// We can fetch linked records using the "getLinkedRecords()" method of
// the record instance. We should always supply the maximum number of
// records to return, plus the sorting order for the returned records.
const securedInvestmentsRelation =
(await sirenapi.Relation.getRelationsByLabel('secured'))[0];
const investments = await record.getLinkedRecords(
securedInvestmentsRelation,
{
size: 1000,
orderBy: { field: 'raised_amount', order: 'desc' },
cancelPromise // Pass the cancelPromise in the query options
}
);
// Now, given our investments we can calculate the total raised amount.
computedData.raisedAmount = 0;
for (const investment of investments) {
const amount =
(await investment.getFirstRawFieldValue('raised_amount')) || 0;
computedData.raisedAmount += amount;
}
}
}
function valueString(value) {
switch (value) {
case undefined: return <i>{loading}</i>;
case null: return <i>No data</i>;
default: return value;
}
}
function currencyString(value) {
switch (value) {
case undefined: return <i>{loading}</i>;
case null: return <i>No data</i>;
case 0: return <i>No investments</i>;
default: return `${value} $`;
}
}
/**
* A "view" perspective rendering function.
*
* Receives an "input" with "computedData" retrieved by the "enrich"
* function.
*
* Returns the rendered view as a React node.
*/
function reactView({ computedData }) {
return (
<EuiText>
<h1>
<EuiTextColor color="success">
<EuiIcon type="cheer" />
{valueString(computedData.companyName)}
</EuiTextColor>
</h1>
<p>Location: {valueString(computedData.location)}</p>
<p>Total raised amount: {currencyString(computedData.raisedAmount)}</p>
</EuiText>
);
}
/**
* A "binary" perspective rendering function.
*
* Like the "view" perspectives, the "binary" perspectives receive an
* input object with the computed data that prompted the download.
*
* Binary perspective return an object representing the static resource.
*/
async function buildJsonDownload({ computedData }) {
const json = JSON.stringify(computedData, null, 2);
return { filename: 'data.json', content: json };
}
function buildPdfDownload({ computedData }) {
// The identifier of the pdf template. Should be updated with your identifier.
const templateId = 'r10S7Ky7Y';
const filename = `${computedData.companyName}.pdf`;
return { filename, templateId, data: computedData };
}
function buildDocxDownload({ computedData }) {
// The identifier of the docx template. Should be updated with your identifier.
const templateId = '1-pEMybJG';
const filename = `${computedData.companyName}.docx`;
return { filename, templateId, data: computedData };
}
/**
* "registerPerspectives()" is called to register the "perspectives".
*
* The "view" property declares a list of registered "view" perspectives
* which will be used to display the record in the user interface.
*
* The "binary" property declares a list of registered "binary"
* perspectives which will be used to download the record representation.
*
* "initalData" is an optional property used to set the initial data prior
* to any data fetching taking place.
*
* "enrich" is an optional function used to fetch data and process it. This
* data will then be used in the "render" function.
*
* "render" is the function that will build the perspective output.
*/
context.registerPerspectives({
view: {
Tutorial: {
initialData: getInitialData,
enrich: enrichRecordData,
render: reactView
}
},
binary: {
'Json report': {
initialData: getInitialData,
enrich: enrichRecordData,
render: buildJsonDownload
},
'Pdf report': {
initialData: getInitialData,
enrich: enrichRecordData,
render: buildPdfDownload
},
'Docx report': {
initialData: getInitialData,
enrich: enrichRecordData,
render: buildDocxDownload
}
}
});
Next steps
For more information about scripting refer to the Scripting API documentation.