Complete template script example

This document describes the usage of version 1 of Template scripts which is deprecated. For step-by-step instructions on how to create templates with version 2 see Templating and reporting.

const { DataRecord, DataModelEntity, Relation } = sirenapi;
const { EuiText, EuiTextColor, EuiIcon } = Eui;

const loading = <i>Loading ...</i>;

const pdfTemplateId = 'YEtGlkrgc7'; // these need to be changed with those you have in JSreport
const htmlTemplatedId = '1sMaIKU0Y';
const docxTemplatedId = 'XIJ-moX4V'

/**
 * Common function for data fetching, used by all views/downloads.
 */
async function fetchRecordData(input, recordData) {
  const { record, dataModelEntity, cancelPromise } = input;

  // It's best to bail out early on 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.
  recordData.companyName = await record.getLabel();

  // We can fetch linked records using the getLinkedRecords() Record method. 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
  });

  // Now, given our investments we can calculate the total raised amount.
  let raisedAmount = 0;
  for (const investment of investments) {
    const amount = (await investment.getFirstRawFieldValue('raised_amount')) || 0;
    raisedAmount += amount;
  }

  recordData.raisedAmount = raisedAmount;
}

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} $`;
  }
}

/**
 * Explicit data to React transform function, to be used for both partial and final renders.
 */
function reactView(recordData) {
  return (
    <>
      <EuiText>
        <h1>
          <EuiTextColor color="success"><EuiIcon type="cheer" /> {valueString(recordData.companyName)}</EuiTextColor>
        </h1>
        <p>Total raised amount: {currencyString(recordData.raisedAmount)}</p>
      </EuiText>
    </>
  );
}

/**
 * View function for the Record Viewer. It's responsible for:
 *
 *  1. Fetching all necessary data to display for the input record
 *  2. Building a React-based view of the fetched data
 *
 * This input object has the following properties:
 * - record: DataRecord instance for the displayed record
 * - dataModelEntity: DataModelEntity instance for the data model entity that prompted the record display
 * - render: A function that we can use to progressively render the record view
 * - cancelPromise: A promise that gets rejected when execution should be stopped (the user changes record or closes the Record Viewer)
 *
 * The returned value is the final React node rendered in the Record View > Overview tab.
 */
async function buildRecordView(input) {
  const { render } = input;

  const recordData = {};
  const timerId = setInterval(() => render(reactView(recordData)), 200);

  try {
    await fetchRecordData(input, recordData);
  } finally {
    clearInterval(timerId); // Clean up automatic updates before quitting
  }

  return reactView(recordData);
}

/**
 * A download function.
 *
 * Like to the record view, download functions receive an input object with a record and data model entity that
 * prompted the download.
 *
 * The download function will not return anything - it just needs to start a download of the record's data.
 */
async function buildJsonDownload(input) {
  const recordData = {};
  await fetchRecordData(input, recordData);

  const json = JSON.stringify(recordData, null, 2);
  sirenapi.Reporting.downloadString(json, 'data.json', 'application/json');
}

function buildDownload(type, templateId) {
  return async function (input) {
    const recordData = {};
    await fetchRecordData(input, recordData);

    sirenapi.Reporting.download(templateId, recordData, `${recordData.fullNameString}.${type}`);
  }
}

/**
 * Call registerTemplate() to enable the views and downloads available in the script.
 *
 * The "recordView" property declares the view used in the Record Viewer's Overview tab.
 * The "download" property associates a file type to the associated download function.
 */
context.registerTemplate({
  recordView: buildRecordView,
  download: {
    json: buildJsonDownload,
    pdf: buildDownload('pdf', pdfTemplateId),
    docx: buildDownload('docx', docxTemplatedId),
    // ...More file types can be added as required
    html: buildDownload('html', htmlTemplatedId)
  }
});

Next steps

For more information about scripting refer to the Scripting API documentation.