I’ve spent the last few days learning about my new favorite serverless app development platform, Atlassian Forge. It lets you easily develop apps for Confluence, JIRA, and more using JavaScript, and even comes with some really nice UI widgets you can use in their UI kit. While not the main subject of this article, one of my favorite things about their tools is that they make it very simple to store credentials encrypted for use with your Forge app – it’s built into the Forge CLI and is a breath of fresh air for those familiar with more complicated solutions like Amazon’s Key Management Service. Anything to make it easier for folks not to accidentally commit their tokens to GitHub!
Those snazzy UI elements may start to feel a bit constricting if you’re looking to display the results from your favorite REST API. Take for example the Table widget. The docs are very helpful explaining all the features, but what if you don’t know how many elements you’re going to have? What if you have a key that stores a list with a variable number of objects, and maybe you don’t know what their attributes are going to be yet? Maybe there’s a computation you need to do with the data and display the result? What if you don’t want to have any degree of repetition, defining each row yourself? We need a way to programmatically create a table (or similar container- doing this for a button set or tag group is left as an exercise to the reader!).
This is where the humble map comes in. Maps are common in JavaScript- they hold key value pairs. You can build a map that then lets you iterate over all the objects you want to display- even if you don’t know how many there are going to be! The UI kit markdown can look static but you can actually use JavaScript like maps inside your UI kit responses from Forge! You can also compute new results not in your data source right in line. If you didn’t know this, you may be tempted to do something like the following. Let’s say you have an API that returns some team group members for a given project. It has a list of team members under the key ‘members’. You may be tempted to write a return like this in your Forge app to put them in a table inside an inline dialogue:
const response = await fetch(myfaketeamqueryurl, {
method: "get",
headers: { "Content-Type": "application/json" },
});
const data = await response.text();
const App = () => (
<Table>
<Head>
<Cell>
<Text>Name</Text>
</Cell>
<Cell>
<Text>Task Completion (out of 100%)</Text>
</Cell>
</Head>
<Row>
<Cell>
<Text>data.members[0].name</Text>
</Cell>
<Cell>
<Text>data.members[0].tasksCompleted</Text>
</Cell>
</Row>
<Row>
<Cell>
<Text>data.members[1].name</Text>
</Cell>
<Cell>
<Text>data.members[1].tasksCompleted</Text>
</Cell>
</Row>
<Row>
<Cell>
<Text>data.members[2].name</Text>
</Cell>
<Cell>
<Text>data.members[2].tasksCompleted</Text>
</Cell>
</Row>
</Table>
);
And so on, and so forth, until you’re writing markup all day, your boss is mad, and you still haven’t solved the issue that you don’t know how long the ‘members’ list is. You also are just putting the number of tasks completed- no the percentage score your API doesn’t return and you need to find a way to compute within Forge.
Well it turns out the following will work just fine, and is far shorter:
const response = await fetch(myfaketeamqueryurl, {
method: "get",
headers: { "Content-Type": "application/json" },
});
const data = await response.text();
const numberOfTasks = 15;
const App = () => (
<Table>
<Head>
<Cell>
<Text>Name</Text>
</Cell>
<Cell>
<Text>Email</Text>
</Cell>
</Head>
{Object.keys(data).map(members => (
<Row>
<Cell>
<Text>{name}</Text>
</Cell>
<Cell>
<Text>{Math.round(tasksCompleted / numberOfTasks * 100)}%</Text>
</Cell>
</Row>
))}
</Table>
);
We now accommodate however many members there are (even 0!) and do the math for our score right in line. Forge will evaluate all of this JavaScript and programmatically create as many lines as you want.
Why am I sharing this? It’s a key part of the UI of my new Forge app PriorWise! As part of my submission to the 2023 Codegeist Unleashed Hackathon I use this trick to list as many patents and papers as I can based on a user’s query. It lets you highlight some text or even search a full page for relevant patents and research papers, known as prior art. This helps innovators find out if they are infringing on an existing idea, or inform new avenues of research and collaboration. It uses AI to find results that are similar in terms of meaning and topic. While I don’t always know how many results I’ll get back, if they will have images or not, and I still need to compute a similarity score for the user, I know Forge and UI kit will take care of all of this and display an organized result for my users. This stumped me for a bit, don’t let it stump you!
