You are reading the documentation for an outdated Corteza release. 2023.9 is the latest stable Corteza release.

Samples

Use these samples as a starting point for your integrations.

Make sure to adjust the parameters to fit your instance.

Triggers

Explicit trigger (button)

triggers ({ on }) {
  return on('manual')
    .for('compose:record')
    .uiProp('app', 'compose')
},

Implicit trigger (automatic)

// Before something
triggers ({ before }) {
  // You can pass in multiple events: create, update, delete
  return before('create', 'update')
      .for('compose:record')
      .where('module', 'Module1')
},

// After something
triggers ({ after }) {
  // You can pass in multiple events: create, update, delete
  return after('create', 'update')
      .for('compose:record')
      .where('module', 'Module1')
},

Deferred (interval)

// Every day at 2AM
triggers ({ on }) {
  return on('interval')
    .every('0 2 * * *')
},

Deferred (timestamp)

// On christmas eve
triggers ({ at }) {
    // You can pass multiple timestamps (timestamp1, timestamp2, ..., timestampN)
  return at('2020-12-24T21:00:00Z')
},

On HTTP request

// On christmas eve
triggers ({ on }) {
  return on('request')
    .where('request.path', '/some/path/here')
    // HTTP protocol; GET, POST, PUT, PATCH, DELETE
    .where('request.method', 'POST')
    .for('system:sink'),
},

Server scripts

Generic implicit script

Use this generic template to cover 90% of use-cases.

Generic implicit script:
export default {
  label: "label goes here",
  description: "description goes here",

  // Use the ones you need, delete the rest
  triggers ({ before, after, on, at }) {
    return before('event goes here')
      .where('constraint goes here')
      // Add/remove constraints here
  },

  // remove async if you aren't doing any async operations
  // use object destructuring for args and ctx
  async exec(args, ctx) {
    // Code goes here
  },
}

Before saving a record

Example use-cases:
  • calculate complex fields

  • value validation

  • create a changelog entry

It would be best if you used field expressions for most field validations and value calculations.

DevNote: provide some references.

Before saving a record:
export default {
  label: "label goes here",
  description: "description goes here",

  triggers ({ before }) {
    return before('create', 'update')
      .for('compose:record')
      .where('module', 'module goes here')
      .where('namespace', 'namespace goes here')
  },

  // If you don't need the Compose helper, remove it
  async exec ({ $record }, { Compose }) {
    // Code goes here

    return $record
  },
}

After saving a record

Example use-cases:
  • notify the owner about the change

  • send the change to an external integration

  • create a changelog entry

If you want to change the value, you should use Before saving a record instead.

After saving a record:
export default {
  label: "label goes here",
  description: "description goes here",

  triggers ({ after }) {
    return after('create', 'update')
      .for('compose:record')
      .where('module', 'module goes here')
      .where('namespace', 'namespace goes here')
  },

  // If you don't need the Compose helper, remove it
  async exec ({ $record }, { Compose }) {
    // Code goes here
    // Note: the return value is ignored
  },
}

Generic on click action

Example use-cases:
  • OAuth flows

  • send notifications

  • render documents

Generic on click action:
export default {
  label: "label goes here",
  description: "description goes here",

  triggers ({ on }) {
    return on('manual')
      // vv Don't remove the next line vv
      .uiProp('app', 'compose')
  },

  // If you don't need the Compose helper, remove it
  async exec (args, { Compose }) {
    // Code goes here
  },
}

Process record on click

Example use-cases:
  • email the record contact

  • email the record owner

  • generate report for the specific record

Process record on click:
export default {
  label: "label goes here",
  description: "description goes here",

  triggers ({ on }) {
    return on('manual')
      .for('compose:record')
      .where('module', 'module goes here')
      .where('namespace', 'namespace goes here')
      // vv Don't remove the next line vv
      .uiProp('app', 'compose')
  },

  // If you don't need the Compose helper, remove it
  async exec ({ $record }, { Compose }) {
    // Code goes here
    // Note: unless false or an error, the return value is ignored
  },
}

Respond to an HTTP request

Example use-cases:
  • creating records from an external form

  • document approval/signature tracking

  • credit card payment capturing

You will need to add the base-64 package.

Respond to an HTTP request:
// Don't forget to add this package
import base64 from 'base-64'

export default {
  label: "label goes here",
  description: "description goes here",

  security: {
    runAs: 'user goes here',
  },

  triggers ({ on }) {
    return on('request')
      .where('request.path', '/path')
      .where('request.method', 'POST')
      .for('system:sink')
  },

  async exec ({ $request, $response }) {
    // The body is base64 encoded.
    // If we're working with json content, don't forget the JSON.parse
    const body = JSON.parse(base64.decode($request.rawBody))

    // Do something with the data...
    // ...

    // Prepare the response
    $response.status = 200
    $response.header = { 'Content-Type': ['application/json'] }
    $response.body = JSON.stringify({ result: 'example' })

    // and send back everything
    return $response
  }
}

Client scripts

Before submitting the form

Example use-cases:
  • calculate complex fields

  • value validation

  • pre-fill missing values

You can set the default value for a field in the module editor.

DevNote: provide some links.

Before submitting the form:
export default {
  label: "label goes here",
  description: "description goes here",

  triggers ({ before }) {
    return before('formSubmit')
      .for('compose:record')
      .where('module', 'module goes here')
      .where('namespace', 'namespace goes here')
  },

  // If you don't need the Compose helper, remove it
  async exec ({ $record }, { Compose }) {
    // Code goes here
    // Note: you don't need to return the $record; it's provided by reference
  },
}

Generic on click action

Example use-cases:
  • OAuth flows

  • send notifications

  • render documents

Generic on click action:
export default {
  label: "label goes here",
  description: "description goes here",

  triggers ({ on }) {
    return on('manual')
      // vv Don't remove the next line vv
      .uiProp('app', 'compose')
  },

  // If you don't need the Compose helper, remove it
  async exec (args, { Compose }) {
    // Code goes here
  },
}

Process record on click

Example use-cases:
  • email the record contact

  • email the record owner

  • generate report for the specific record

Process record on click:
export default {
  label: "label goes here",
  description: "description goes here",

  triggers ({ on }) {
    return on('manual')
      .for('compose:record')
      .where('module', 'module goes here')
      .where('namespace', 'namespace goes here')
      // vv Don't remove the next line vv
      .uiProp('app', 'compose')
  },

  // If you don't need the Compose helper, remove it
  async exec ({ $record }, { Compose }) {
    // Code goes here
    // Note: unless false or an error, the return value is ignored
  },
}

Page block samples

Record list samples

Filtering

Record list pre-filtering supports value interpolation that is relative to the content; such as a record.

Available variables:
  • record: current record (when available)

  • recordID: current record’s recordID (when available)

  • ownerID: current record’s owner (when available)

  • userID: current user’s userID

Show only records created this year

YEAR(created_at) = YEAR().

Show only records linked to the viewed record

related_contact = ${recordID}.

Show only active contacts

is_active = '1'.

Show lost opportunities

status = 'closed/lost'.

Sorting

Sort by latest

created_at DESC.

Sort by latest and opportunity stage

created_at DESC, stage DESC.

Metric page block samples

Divide the result by 1000 to show cost in thousands

v / 1000

Round result to remove decimal places

Math.round(v)

Round result to remove decimal places (round up)

Math.ceil(v)

Round result to remove decimal places (round down)

Math.floor(v)

Round result to two decimal places

Math.round(v * 100) / 100

Expressions use standard JavaScript syntax, so you can use any standard JavaScript expression.

You can specify rounding with the value formatting.