100% agree! A lot of my requests here are directly related to this.
Here are some things I can’t currently do with no-code:
- “Reach through” a Lookup to update the referenced entity.
- Change the Status of a related entity.
- Use References to look up a related entity:
// If a Task's "Project" field is uninitialized, and there is a "Meeting Notes"
// that references the Task, set the Task's "Project" field from the MN's "Default Project".
// Script parameters
const ENTITY_LINK_FIELD = 'Project' // Task field that needs to be set
const PARENT_TYPE = 'Project/Project' // Type we want to find a link to (value for)
const REF_ENTITY_TYPES = ['Clients/Meeting Notes'] // Types that have "Default Project" field
const REF_ENTITY_LINK_FIELD = 'Default Project' // Name of the field to copy
const fibery = context.getService('fibery')
// const log = console.log
// Iterate through the entities
for (const entity of args.currentEntities) {
// Set the Project field if empty
if (entity[ENTITY_LINK_FIELD].id == null) {
// Get all references to the Task
const entityWithRefs = await fibery.getEntityById(entity.type, entity.id, ['References'])
// Look for a reference to to a type with "Default Project" field (i.e. Meeting Notes)
for (const ref of entityWithRefs['References']) {
// Get referencing doc
const refDoc = await fibery.getEntityById('Collaboration~Documents/Reference', ref['Id'], ['FromEntityId', 'FromEntityType'])
const refType = refDoc['FromEntityType'].name
if (refType == PARENT_TYPE) {
// The referring entity is the actual PARENT_TYPE (so its ID can be used directly)
// I.e. a Task was created/referenced in a Project's Rich Text field
const refEntity = await fibery.getEntityById(refType, refDoc['FromEntityId'], ['Name'])
// log(` refType == PARENT_TYPE: ${refType}, ${refDoc['FromEntityId']} ${refEntity.id}`)
await fibery.updateEntity(entity.type, entity.id, { [ENTITY_LINK_FIELD]: refEntity.id })
break
} else if (REF_ENTITY_TYPES.includes(refType)) {
// Found a suitable referring entity (i.e. that has a "Default Project" field)
const refEntity = await fibery.getEntityById(refType, refDoc['FromEntityId'], ['Name', REF_ENTITY_LINK_FIELD])
if (refEntity != null && refEntity[REF_ENTITY_LINK_FIELD].id != null) {
const refId = refEntity[REF_ENTITY_LINK_FIELD].id
await fibery.updateEntity(entity.type, entity.id, { [ENTITY_LINK_FIELD]: refId })
break
}
}
}
}
}
- Call an external webhook
- Do something to every entity in a Collection, conditional upon the entity’s State, etc.
- Trim blanks from a field (I tried a Formula, didn’t work )
- Access an entity’s UUID
- Treat a Formula field like a Lookup/Reference (if it returns an entity).
- Do anything with Documents (like create & link).
- Work with Rich Text:
// Create and link a new Meeting Notes entity to a Client
const log = console.log
const dump = (obj) => JSON.stringify(obj, null, 2)
const fibery = context.getService('fibery')
const MEETING_NOTES_TYPE = 'Clients/Meeting Notes'
const TEMPLATE_DOC_ID = "b62eaad0-e02b-11ec-b6d4-31b05e8bc8ae"
const template_DocName = 'Meeting Notes TEMPLATE'
const fmt = 'html'
function assert(b, msg) { if (!b) throw new Error(msg) }
// Retrieve the contents of the Meeting Notes TEMPLATE Document
const template_Secret = await getDocumentSecret(TEMPLATE_DOC_ID)
assert(template_Secret, `"${template_DocName}" Document not found - ID "${TEMPLATE_DOC_ID}"`)
const template = await fibery.getDocumentContent(template_Secret, fmt)
assert(template, `No content retrieved for "${template_DocName}" Document - ID "${TEMPLATE_DOC_ID}"`)
for (const client of args.currentEntities) {
// Create a new Meeting Notes entity and link it to the Client
const meetNotes = await fibery.createEntity(MEETING_NOTES_TYPE, { 'Client ID': client['Public ID'] })
// Build the new Meeting Notes Description content via mustache macro replacement of the Template's contents
const macros = {}
const newDescription = template.replace(/\{\{\s*(\w+)\s*\}\}/g,
(match, name) => (typeof macros[name] === 'string' ? macros[name] : ''))
//log('new Description: ' + text)
// Update the new Meeting Notes Description content
await fibery.setDocumentContent(meetNotes.Description.Secret, newDescription, fmt)
}
async function getRichTextContent(entity, fieldName, fmt) {
const secret = entity[fieldName].Secret
return await fibery.getDocumentContent(secret, fmt)
}
async function getDocumentSecret(docId) {
const view = await fibery.getEntityById('fibery/view', docId, ['fibery/meta']);
return view['fibery/meta']['documentSecret'];
}
- De-duplication (looping, comparing, deleting, etc) – i.e. enforcing the uniqueness of entities by a key value (post-hoc is better than nothing!)
// Search for identical Roles (by Name) and delete all but the oldest one
const fibery = context.getService('fibery')
const entity_type = args.currentEntities[0].type
const SPACE_NAME = 'Users'
for (const entity of args.currentEntities) {
// Find all identical Roles
const query = `{findRoles( name:{is: "${entity.name}"} orderBy:{creationDate: ASC}) {id}}`
const result = await fibery.graphql(SPACE_NAME, query)
// Delete any duplicates
if (result && result.data.findRoles.length > 1) {
const roles = result.data.findRoles
for (let i = 1; i < roles.length; i++) {
// console.log(`Deleting: ${roles[i].id}`)
await fibery.deleteEntity(entity_type, roles[i].id)
}
}
}
-
Because no-code Rule conditions can only test an entity’s own fields (i.e. they can’t test the fields of related entities or use arbitrary Formulas), I am forced to bring in more fields from related entities as Lookups/Formulas, and I resist doing this because it litters up my DB’s with all sorts of unwanted fields.
-
The lack of a “Description” or “Comments” area for each DB’s Automations page (and for individual Rules/Buttons) is frustrating. I would really hate to inherit a complex system like this with such little documentation. Scripts at least allow me to do that.
Ideally it should be just as easy to “synthesize” a join anywhere (instead of needing to manually construct a new DB to represent it). E.g. in a Table view, have the ability show any arbitrarily related fields (as columns) AND allow the user to edit them; or in automations, allow any related fields (and formulas) to be tested in the Rule conditions (we need formulas there!). I think this ability alone would relieve most of the architecture/code limitation issues I struggle with – big things like lack of polymorphism.
That, plus the ability to hide fields (I know it’s coming), but that’s really more of a band-aid to paper over the need to drag in so many fields with Lookups/Formulas.