Guide
There are a couple of actions that can create comments, or change the contents of Rich Text fields of an entity. All of these actions have a text area that supports the markdown template.
Markdown basics
Fibery supports almost all features of basic markdown syntax in Rich Text fields and documents.
Please check this guide and apply it for actions with a markdown template.
This is an example of a simple markdown template:
# Hello
Hi, **dear friend**. Nice to meet you.
This one will work for adding checklists
### My checklist
- [ ] Conquer markdown
- [ ] Procrastinate for the rest of the day
### My nested checklist
- [x] Task 1
- [ ] Task 2
- [x] Subtask A
- [ ] Subtask A
- [x] Task 3
Callout blocks
To add a callout block of a specific color with a custom icon, use this syntax:
> [//]: # (callout;icon-type=icon;icon=sun;color=#fc551f)
> My pretty orange callout
> has multiple
> lines
With an emoji instead of an icon:
> [//]: # (callout;icon-type=emoji;icon=:tangerine:;color=#FBA32F)
> My pretty orange callout
> has multiple
> lines
Using entity fields
You can refer to entity fields in the template when there is a need to use field values.
The syntax is {{Field Name}}.
Using to-one relations
Use . when you need to put a values from a relation item into the template: {{Relation Name.Field Name}}.
This way for referencing entity fields in markdown is different to the syntax used in Formulas. Specifically, field names that have spaces do not need to be enclosed in square brackets.
Here we will get the entity's Name and its State Name:
# My name is {{Name}}
My current status is {{State.Name}}
Using to-many relations
You can get the contents of a collection field (to-many relation) into a document, but you need to decide how these entities' values should be formatted. You can format collection fields as a table, a bulleted list or a comma-separated list using special syntax (or you can use Javascript to format in other ways).
Collection → Table formatting
There is a way to include entity collections into the output document: {{Collection Name:Field1,Field2,...,FieldN}}. The result of the collection shortcut is a table.
Let's say Story has a collection of Bugs. You can print them into a document like this:
## Quick Overview of {{Name}}
Current state is **{{State.Name}}**.
### Bugs
{{Bugs:Name, State.Name}}
1. We created a button with "Add comment" action
2. The result of the button click:
Collection → bulleted list formatting
Use {- Collection Name:Field1 -} to create a bulleted list.
For example, {- Assignees:Name -} will produce:
Collection → comma-separated list formatting
Use {= Collection Name:Field1 =} to create comma-separated list.
For example, {= Assignees:Email =} will produce:
teddy@fibery.io, jerry@fibery.io
More complex formatting
For more complex formatting, you can use Javascript on collections if you declare them first using {! Collection Name:Field Name !} e.g.
{!Tasks:Id,Name!}
<%= Entity.Tasks.map((task) => task.Name).join(` | `) %>
See later for how to use Javascript.
You can only get collection fields from one link deep. That is to say, if you have a Product, linked to Features, which have Assignees, you can use markdown at the Product level to get 'simple' field values of its Features, e.g.{{Features:Name}} but you can't get values from Features' collections, i.e.{{Features.Assignees:Name}} will not work.
Using rich text fields
You can use Rich Text fields in automation templates. It works for native entity fields, fields accessible via 'to-one' relations and even collections. Here are some examples:
Hello: {{Description}}
This is one-to-one: {{Epic.Description}}
This is collection {{Bugs:Description}}
In case you're wondering, if you're referencing a rich text field in your markdown, and the content of the field includes text which follows the {{…}} notation, this text will not be dynamically replaced. In other words, the evaluation of fields only occurs for one level.
Access rich text field in collections
You can access rich text fields in collections attached to an entity in markdown templates in automations and AI prompts. What does it mean?
For example, you have a list of Highlights linked to some Feature. So you can create an AI prompt that will take content of all these highlights and generate a feature spec for you based on customers problems.
https://youtu.be/ji1fvkGXC2I?feature=shared
Here is the prompt, for the reference.
You are a very experienced product manager. You need to write a good specification for a feature "{{Name}}" based on customers requests. Let's work on this step by step.
First, generate a short list of main problems based on customers feedback Make problems unique, do not repeat them. Generate a list of problems via bullet points. Here is the customers feedback below:
"""
{- Highlights:Highlight -}
"""
Next step. Now merge similar problems and return a list of main problems only. No more than 5 problems.
Next step. Now think and invent a feature specification for feature {{Name}} that will solve the problems above.
Return in the following template:
## Problems
[list of main problems above as bullet points]
## Solution
[brief solution overview]
Here are few examples how to access rich text fields:
Get all highlights content: {- Highlights:Highlight -}
Get all comments content: {- Comments:Text -}
Get all bugs descriptions linked to a feature: {- Bugs:Description -}
Get all meeting notes content linked to a project: {- Project:Summary and Notes -}
Note: There is a limit of 100 entities in a collection, so if you have large collections it will just cut remaining entities due to performance limitations.
Mentioning Entities and Users
To mention an Entity or a colleague (User) via markdown, you need to utilise the database ID and the entity's UUID:
[[#^DB_ID/ENTITY_ID]] is important, [[#@USER_DB_ID/USER_ENTITY_ID]] please take a look.
A raw example:
[[#^7c2da640-2abf-11ed-ac0b-05d5e363c932/7d3cf360-2abf-11ed-ac0b-05d5e363c932]] is important, [[#@1b728600-af9c-11e9-95b5-2985503542d7/b5754020-0ab5-11ea-848a-cdd700770a5f]] please take a look
The easiest way to get all the Database IDs apart from querying the API, is via this small script:
const fibery = context.getService('fibery');
const schema = await fibery.getSchema();
const dbID = schema['typeObjects'].filter((obj) => obj.name == Entity.Type)[0]['id'];
You can find more details on scripts in a dedicated Scripts in Automations guide.
Using Entity Fields:
[[#^7c2da640-2abf-11ed-ac0b-05d5e363c932/{{Goal.Id}}]] is important, [[#@1b728600-af9c-11e9-95b5-2985503542d7/{{Team.Leader.Id}}]] please take a look
Here is an example. You have an Author database with a collection of Books. You want to create Buttons that insert a list of references into Author's description rich edit field.
You should create a new Action Button for Author database, select Append content to Description action and write the following template code:
{!Books:Id!}
<%
const fibery = context.getService('fibery');
const schema = await fibery.getSchema();
const dbID = schema['typeObjects'].filter((obj) => obj.name == 'Strategy/Book')[0]['id'];
%>
<%= Entity.Books.map((book) => "[[#^" + dbID + "/" + book.Id + "]]").join('\n') %>
Markdown Templates AI Assistant
You can use AI to create markdown templates in automation action for rules or buttons. Use Ask AI button near any markdown template. It can generate quite dumb templates with just some fields, or some clever templates using scripts. Check it out:
https://youtu.be/UJpQO9Dc1AI
Using Javascript code and Fibery API in templates
Javascript code and Fibery API can be used in templates. Javascript code can be executed using <% const sample = 1; %> syntax. You may place output from your code into the template using <%= sample%> syntax.
An entity can be referenced as Entity if you need to make calls to Fibery API and retrieve additional entity data. Entity contains Id and Type properties.
Here is an example of using Javascript and Fibery API in a template.
### Overview of assignees
<%= Entity.Type %> (#<%= Entity.Id%>)
#### Assignees
<%
const fibery = context.getService('fibery');
const entityWithAssignees = await fibery.getEntityById(Entity.Type, Entity.Id, ['Assignees']);
entityWithAssignees.Assignees.forEach((assignee) => {
%>
- <%= assignee.Name %>
<% });%>
Date of comment: <%= new Date()%>
The output of this template if it is used for "Add Comment" action can be found below
Javascript code in markdown templates has some limitations for security reasons.
Another example — using Javascript to show prettier dates
instead of <%= new Date()%> you can use:
<%
let d = new Date(2010, 7, 5);
let ye = new Intl.DateTimeFormat('en', { year: 'numeric' }).format(d);
let mo = new Intl.DateTimeFormat('en', { month: 'short' }).format(d);
let da = new Intl.DateTimeFormat('en', { day: '2-digit' }).format(d);
%>
<%= `${da}-${mo}-${ye}` %>
Using async calls during collection traversal
During collection traversal, it is sometimes necessary to use async calls to Fibery API.
In this case use for … of syntax instead of collection.forEach(…) .
Here is an example:
# Closed Tickets in Release
{!Tickets:Id,Name,IdOfTicketInExternalSystem!}
<%
const http = context.getService('http');
for (let ticket of Entity.Tickets) {
const content = await http.getAsync(`https://external-system-url/tickets/${ticket.IdOfTicketInExternalSystem}`);
%>
## <%= ticket.Name %>
<%= content %>
<% } %>
Current User
Every template receives information about the current user if the rule was triggered by the user:
Changes were made by **{{CurrentUser.Email}}**
Note: If a rule has been triggered by something other than a user action, e.g. when the value of a formula field containing the Today() function changes, then {{CurrentUser}} will return empty object.
Note: {{CurrentUser.Notes}} won't work for a rich-text Field, use the scripted approach below instead.
Previous Value Access for Automation Rules
When Update Trigger is selected in the Automation Rule, Markdown template receives information about Previous Value of the updated entity:
Name changed from {{PreviousEntity.Name}} to {{Name}}
If the Name field changed from “Old Name” to “New Name”, the rendered text will be:
Name changed from Old Name to New Name
Example: reference field
State changed from {{PreviousEntity.State.Name}} to {{State.Name}}
If State changed from “In Progress” to “Done”, the rendered text will be:
State changed from In Progress to Done
PreviousEntity does not support collection fields. e.g. {{PreviousEntity:Bugs}} will not return a value.
Using PreviousEntity in <%= … %> templates
If you use the <%= … %> syntax, you can also access the previous entity via PreviousEntity.
PreviousEntity object here contains only one property – the changed field specified in Trigger.
Examples of PreviousEntity object value:
If Changed Field is a primitive field: {"Text Field": "previous text field value"}.
If Changed Field is a reference field: {"State": {id: "previousStateIdUuid"}.
If several changed fields are used in a Trigger, PreviousEntity will be an empty object.
Insert Comments or Documents into template
Find below an example on how insert last comment into template
{! Comments:Author.Name,Document Secret !}
<%
const fibery = context.getService('fibery');
const lastComment = Entity.Comments[Entity.Comments.length-1];
%>Comment added for {{Name}} by <%= lastComment['Author.Name'] %>
<%= await fibery.getDocumentContent(lastComment['Document Secret'], 'md') %>
FAQ
Why does Trigger reaction time seem to be inconsistent for Entity Updated > Rich Text field?
Here you can read full discussion and ask more questions.
Overall given that a sentence typed in a rich text field can contain dozens of typed letters, it doesn’t make sense to trigger on each new character. Accordingly, changes are ‘batched’ together, and an automation is only triggered when Fibery thinks there has been a natural break in editing.
Also, each workspace has an automation ‘queue’ so triggered automations may not execute immediately if others are still active/pending.