Guide
Bi-directional links are ad-hoc connections and work for all database entities in Fibery. When you mention an entity via # or [[ , you will see the mention in the entity itself.
For some use cases, like feedback management, it is better to use Highlights.
Creating an entity mention
Use # or [[ to link to entities or views in rich text. For example, here is the link to a release May 26, 2022 / Customize pinned Fields, rename Workspace, 16 fixed bugs
Back-links section in an entity view
Every entity has a References section in the main area where all links to this entity are displayed. For example, here are the references for the releases above:
It shows when the link was created, link context, who created it and enables fast navigation to the exact place in a document or entity.
Navigate to the exact place in a document or entity
Put a mouse cursor over reference section and find Open arrow.
Click Open arrow and a document or entity will open in the left panel.
Customize Entity Mention fields to show
You can customize which fields to show for mentioned entities. Put the cursor on database icon and click …, then select fields you want to be displayed for this database.
This setting is per-database and for all users. It means if you set it up for Feature database, all users will see these fields on mentioned entities.
Use Cases
Here are some use cases for bi-directional links that may inspire you.
Competitors
We use them to link feedback and opinion about Fibery competitors. Thus when you want to see what our leads or customer told us about ClickUp, you can navigate to ClickUp entity and read them here.
Cross-referenced user guide
This user guide uses mentions extensively to glue information together. It works better than usual links, since you can change names of guides and it will be reflected in all places automatically.
FAQ
What is the difference between References and Relations?
Relations are much more powerful and make sense when you need to build Views (ex: group Tasks by Project), or powerful Formulas (show me avg progress on Tasks on this Project), etc.
References can work as ad-hoc light relations, but you can't use them to create views.
Exemple: I wanted to discuss his interview in this meeting ≠ meetings and interviews are formally connected
Here is an insight, that is connected to Interviews, Conversations, Docs and etc. via References
Can References be used in Formulas?
Yes, but capabilities are a bit limited. Here are some examples:
Count number of References
References.Count()
It can be used to count, how many times Feature was requested, Bug was reported, or Insight was collected. Formulas results can be used for prioritization
Count the number of References from specific channels/databases
References.Filter((FromEntityType.Name = "Customer Success/Conversation")).Count()
In this case, we will see how many references do we have from Customer Conversations only.
This may help to better filter reference sources.
Count unique requests
References.Filter(FromEntityType.Name != "Customer Success/Conversation").CountUnique(FromEntityId)
In this case, we will see how many references we have from Customer Conversations only, and also ignore requests, that were done by a single customer. So if one customer asked for a feature 15 times, only one request was counted.
Can't do…
At the moment we can't operate with the source database attributes. For example, we can't create a formula that will calculate all references from conversations where we talked to product teams.
Also, at the moment we can't calculate a weighted score for the request. For example, we can't calculate whether this request for the customer is crucial or just a wish.
How can I batch re-link references?
Unfortunately, the script is the only way to do that.
You need to go through the content of all Rich text fields where there was a linked highlight. It is necessary to use the “JSON” format as below
const content = await fibery.getDocumentContent(documentSecret, "json");
The goal is to find all linked highlight nodes inside the markup like
{ type: 'linkedhighlight', attrs: { id: '6459d4e1-fb9f-49ae-8d1d-7a3a29f0e5fb', meta: { links: [ { typeId: 'e822e844-2424-40f4-a309-9c32b4f27119', id: 'b5d87a90-f35f-11ee-b9f7-11aaf793c597' } ], type: 'linkedhighlight' } } }
Here it is important to modify only those whose TypeId and Id, correspond to the original type ID and the original entity ID with new ones that were obtained after
Most importantly, you also need to change attrs.id to a new random UUID
const newId = utils.uuid()
Here is what can be used as an inspiration :)
function walk(content, matcher, transform) {
if (content === null) {
return null;
}
if (matcher(content)) {
return transform(content);
}
if (Array.isArray(content)) {
return content.map((item) => walk(item, matcher, transform));
}
if (typeof content === "object") {
return Object.fromEntries(Object.entries(content).map(([key, value]) => [key, walk(value, matcher, transform)]))
}
return content;
}
function relinkHighlights() {
const originalEntityTypeId = "e822e844-2424-40f4-a309-9c32b4f27119";
const originalEntityId = "b5d87a90-f35f-11ee-b9f7-11aaf793c597";
const targetEntityTypeId = "target-type-id";
const targetEntityId = "target-id";
const transformed = walk(content, (value) => {
if (typeof value === "object" && value.type === "linkedhighlight") {
return value.attrs.meta.links.some(({typeId, id}) => {
return typeId === originalEntityTypeId && id === originalEntityId;
});
}
return false;
}, (linkedHighlight) => {
return walk({linkedHighlight, id: utils.uuid()}, (value) => {
return typeof value === "object" && value.typeId === originalEntityTypeId && value.id ===originalEntityId;
}, (link) => {
return {
...link,
id: targetEntityId,
typeId: targetEntityTypeId
};
});
});
console.log(transformed);
}
relinkHighlights();
Please, note that this linkedhighlight node is not a public API.
So, if we consider this one as an example:
{
type: 'linkedhighlight',
attrs: {
id: '6459d4e1-fb9f-49ae-8d1d-7a3a29f0e5fb',
meta: {
links: [
{
typeId: 'e822e844-2424-40f4-a309-9c32b4f27119',
id: 'b5d87a90-f35f-11ee-b9f7-11aaf793c597'
}
],
type: 'linkedhighlight'
}
}
}
Here
type and attr - describes a node type and its attributes
id is a node unique identifier, if you change the content of linkedhighlight node you must also update its id (it might not be necessary for other node types).
links holds information about to which Entity in the system this highlighted text is linked to. It was made as an array as we at some point decided that there maybe more than one target, but never did it.
So, link consists of typeId and id it which are Entity Type Id and Entity Id to which your highlighted Text is mapped.
To get typeId you can use Schema
const schema = await fibery.getSchema();
const typeId = schema.typeObjectsByName[`SPACE_NAME/DATABASE_NAME`].id;
If you want to script a button that will be on the Converted Database then the following steps will be like:
iterate on args.currentEntities
e.g. for (const convertedEntity of args.currentEntities) { ...
for each convertedEntity find respective source Entity e.g. by matching their Names using graphql, there you could include entity id in the select clause
request every Rich Text field content in json format for source Entity
call relinkHighlights to get updated json representation of the rich text content
const newContent = relinkHighlights({content, sourceId, sourceTypeId, convertedEntity.id, convertedEntity.type});
update rich text document with new content