In Part 1 of this series, I explained how to generate a plugin and clone the
example command.
In Part 2 I covered finding and loading the package.json manifest and my custom configuration file.
In Part 3, I explained how to load and process source format metadata files.
In Part 2 I covered finding and loading the package.json manifest and my custom configuration file.
In Part 3, I explained how to load and process source format metadata files.
In
Part 4, I showed how to enrich fields by pulling in information stored outside of
the field definition file.
In this week's exciting episode, I'll put it all together and generate the
HTML output. This has been through several iterations :
- When I first came up with the idea, I did what I usually do which is hardcode some very basic HTML in the source code, as at this point I'm rarely sure things are going to work.
- Prior to my first presentation of the plug-in, I decided to move the HTML out to files that were easily changed, but still as fragments. This made showing the code easier, but meant I had to write a fair bit of boilerplate code, but was all I really had time for.
- Once I'd done the first round of talks, I had the time to revisit and move over to a template framework, which was always going to be the correct solution. This was the major update to the plug-in I referred to in the last post.
Template Framework
I'd been using EJS in YASP
(Yet Another Side Project) and liked how easy it was to integrate. EJS
stands for Easy JavaScript templates, and it's well named. You embed plain
old JavaScript into HTML markup and call a function passing the template and
the data that needs to be processed by the JavaScript. If you've written
Visualforce pages or email templates in the past, this pattern is very
familiar (although you have to set up all of the data that you need prior to
passing it to the generator function - it won't figure out what is needed
based on what you've used like Visualforce will!).
A snippet from my HTML page that lists the groups of objects:
<% content.groups.forEach(function(group){ %> <tr> <td><%= group.title %></td> <td><a href="<%= group.link %>">Click to View</a></td> </tr> <% }); %>
and as long as I pass the function that generates the HTML an object with a property of content, that matches the expected structure, I'm golden.
To use EJS in my plug-in, I install the node module, :
npm install --save ejs
(Note that I'm using the --save option, as
otherwise this won't be identified as a dependency and thus won't be added to
the plug-in. Exactly what happened when I created the initial version and
installed it on my Windows machine!)
I add the following line to my Typescript file to import the function that
renders the HTML from the template:
import { renderFile } from 'ejs';
and I can then call renderFile(template, data) to
asynchronously generate the HTML.
Preparing the Data
As Salesforce CLI plug-ins are written in
Typescript by
default, it's straightforward to keep track of the structure of your objects
as you can strongly type them. Continuing with the example of my groups, the
data for these is stored in an object with the following structure:
interface ObjectsContent { counter: number; groups: Array<ObjectGroupContent>; footer?: object; }
Rather than pass this directly, I store this as the content of a more generic
object that includes some standard information, like the plug-in version and
the date the pages were generated:
let data={ content: content, footer: { generatedDate : this.generatedDate, version : this.config.version } };
Rendering the HTML
Once I have the data in the format I need, I execute the rendering function passing the template filename -
note that as this is asynchronous I have to return a promise to my calling
function:
return new Promise((resolve, reject) => { renderFile(templateFile, data, (err, html) => { if (err) { reject(err); } else { resolve(html); } }) })
and my calling function loops through the groups and gets the rendered HTML when the promise resolves, which it writes to the report directory:
this.generator.generateHTML(join('objects', 'objects.ejs'), this.content) .then(html => { writeFileSync(this.indexFile, html); });
Moar Metadata
The latest version of the plugin generates HTML markup for an object's Validation Rules and Record types - the example repo of Salesforce metadata has been updated to include these and the newly generated HTML is available on Heroku at : https://bbdoc-example.herokuapp.com/index.html
Related Posts
- Documenting from the metadata source with a Salesforce CLI Plug-in - Part 4
- Documenting from the metadata source with a Salesforce CLI Plug-In - Part 3
- Documenting from the metadata source with a Salesforce CLI Plug-In - Part 2
- Documenting from the metadata source with a Salesforce CLI Plug-In - Part 1
- Parallel Apex Unit Tests and Salesforce CLI Plug-Ins
- Going GUI over the Salesforce CLI Part 2
- Going GUI over the Salesforce CLI
- Mentz - the Mentee Workflow
- Offline mobile app template plug-in Dreamforce 18 session
- Salesforce CLI Play-by-Play
- Salesforce CLI Cheat Sheet
No comments:
Post a Comment