Blog

Release announcements, helpful tips, and community discussion

9.4

Cerb (9.4) is a feature upgrade released on December 10, 2019. It includes more than 98 new features and improvements from community feedback.

To check if you qualify for this release as a free update, view Setup » Configure » License. If your software updates expire on or after September 30, 2019 then you can upgrade without renewing your license. Cerb Cloud subscribers will be upgraded automatically.

Important Release Notes

Customizable Cards

Record card popups are now fully customizable using widgets; just like workspace dashboards and profiles. Currently, only administrators can add or edit card widgets, and their changes are visible to all workers.

Existing card preferences and search buttons are automatically migrated to the new format.

Previously, card preferences had to be configured from the setup page, which wasn’t well-known or intuitive.

Common card widgets can be quickly added using the package library.

Card widgets

Record Fields

The ‘Record Fields’ card widget displays built-in fields, custom fields, and search buttons for any record.

The displayed record can be specified using placeholders. For instance, on a ticket profile, the fields of the ticket and its organization can be displayed at the same time.

The fields and fieldsets to display are configurable. Fields can be dragged into a desired order. This drastically cleans up profiles by only displaying fields that are important and hiding everything else.

A ‘Show record links’ option determines whether or not to show the ‘Links’ section for adding links and showing a search button for each type of linked record.

A ‘Show empty fields’ option determines whether blank fields will be included in the output. This is disabled by default (i.e. fields with no value are hidden).

Custom search counter buttons can be configured for each instance of the widget. These buttons run a search query using placeholders from the target record and return the number of results. For instance, a different set of search counters could be displayed on an organization fields widget on tickets and on contacts. For tickets, counts of the organization’s ticket history and contacts could be shown.

Attachment Viewer

The ‘Attachment Viewer’ card widget previews the contents of a particular file attachment. When a worker has access, it also provides a download option.

Behavior Tree

The ‘Behavior Tree’ card widget displays an editable decision tree for any behavior.

Classifier Training

The ‘Classifier Trainer’ card widget predicts the best fitting classification from the selected classifier. When a worker has permission, this widget also allows new training examples to be added or imported.

Conversation

The ‘Conversation’ card widget displays messages, comments, and drafts on the target record. The conversation can be paged forward and backward in time.

Knowledgebase Article

The ‘Knowledgebase Article’ card widget displays the specified knowledgebase article.

Sheet

The ‘Sheet’ card widget provides highly customizable tabular output from a dynamic data query.

Custom Fields

Implemented the ‘record links’ custom field type. [#270] [#489] [#1029]

We previously only had a ‘Record link’ (singular).

You can create a new custom record for ‘Tags’ (or industries, countries, states, categories, etc). That also allows you to determine owners for tags, configure their ACL in roles, add custom fields to them, link them (e.g. to kb articles and snippets), etc.

Add a ‘Record Links’ custom field to the record you want to tag (e.g. tickets, orgs, opps), and set its type to ‘Tag’ (your custom record).

That record will now provide a multi-chooser for selecting tags. New tags can be added by workers with access (based on the role and custom record type).

That should be flexible enough to share ‘tags’ between record types when desirable, or using separate record types otherwise (industries vs tags).

We’ll also add a ‘required query’ option for the custom field’s chooser and autocomplete, so you can partition the linked records by properties, fieldset, names, or anything else.

Slider custom fields

Implemented the ‘slider’ custom field type. [#1050]

This works like the importance slider on ticket and task records. The minimum and maximum values are configurable, and default to a range of 0-100.

Comments

Formatting and images in comments

Comments on all record types may now contain Markdown formatting. [#362]

The comment editor is now a text editor with a toolbar that contains actions for: bold, italics, links, lists, images, quoted blocks, code variables/blocks, tables, @mentions, snippets, and preview.

Clicking the preview button displays an exact representation of the new comment in a popup.

Formatting can be enabled or disabled per comment (defaults on).

Comments created from bots, packages, or the API can use the is_markdown=1 field to enable Markdown formatting.

Paste images and attachments while commenting

When commenting on a record, multiple attachments and images may now be pasted from the clipboard. Images will automatically generate an inline image tag.

Drag/drop attachments while commenting

When commenting, files may be dragged and dropped into the ‘Attachments’ section.

Formatting and images in sticky notes

On ticket profiles, sticky notes may contain formatting and inline images.

Custom fields on comments

Comments now properly display any custom fields and fieldsets set on them. Previously these were only visible when editing them.

Custom fields on sticky notes

Sticky notes now properly display any custom fields and fieldsets set on them. Previously these were only visible when editing them.

Comment editor on record editors

When a record editor allows comments (e.g. tickets, tasks), the new comment editor with formatting is now embedded. The ‘Comment:’ heading is a toggle to display the comment editor, which defaults to hidden for simplicity.

Keyboard shortcut to save comment

When writing a comment, a new keyboard shortcut (Alt+Return or Cmd+Return) quickly focuses the save button.

Mail

Schedule outgoing messages for future delivery

Implemented scheduled messages for compose and replies. When sending email, a “When should the message be delivered?” option allows an outgoing message to be queued for future delivery rather than sent immediately. [#590]

For instance, this allows a sales message written on a Friday to be delivered on Monday morning at the start of business in a particular timezone.

A send delay can be enforced for certain workers (e.g. interns) to permit a review before delivery.

At any point before delivery a scheduled message can be rescheduled, or converted back into an editable draft.

Scheduled drafts from the API

In the REST API, the /tickets/compose.json and /tickets/reply.json endpoints now support the send_at option for scheduling a message for future delivery. The option’s value can be a Unix timestamp or human-readable date (e.g. tomorrow 5pm, Dec 31 2020.

Compose

Improved the compose editor

Improved the editor when composing mail. Added a text editor with a toolbar containing formatting options, bot interactions, #commands, snippets, save, and preview.

Paste images and attachments while composing

When composing mail, multiple attachments and images may now be pasted from the clipboard. Images will automatically generate an inline image tag. [#411]

Improved compose drafts

When composing mail, new buttons for ‘Save Draft’ and ‘Discard’ make it much easier to work with drafts. Previously, the compose window could be closed, but it was unclear this would keep the draft open. These abandoned drafts tended to accumulate over time.

Reply

Improved the reply editor

Improved the editor when replying to mail. Added a text editor with a toolbar containing formatting options, bot interactions, #commands, snippets, save, and preview.

Paste images and attachments while replying

When replying to a ticket, multiple attachments and images may now be pasted from the clipboard. Images will automatically generate an inline image tag. [#411] [#1012]

Automatic re-delivery of failed sent messages

When composing or replying to email from any channel (e.g. browser, API, bots), and it fails to send (e.g. SMTP host unreachable, DNS issues), the message will automatically be converted into a queued draft and scheduled for re-delivery in 5 mins.

Cerb will attempt delivery up to 10 times before converting the message back to an editable draft. Each failed delivery attempt will be recorded as a note on the draft.

Previously, failed deliveries through the browser resulted in a draft that had to be manually re-sent, and failed deliveries through the API returned an error.

Broadcast

Improved the broadcast editor

Improved the broadcast editor on bulk update popups. A text editor is now available with a toolbar of placeholders and formatting options. Placeholders suggestions are now provided at the cursor.

When broadcasting to a ticket worklist, it’s no longer necessary to extraneously select a ‘From:’ group. This is now inherited from each ticket.

Signature tokens in broadcast

When bulk updating a worklist, broadcasts may now include a #signature token which will be replaced with the worker’s signature with the correct format, group, and mail template. The signature can be inserted from the toolbar.

Paste images and attachments while broadcasting

When broadcasting to a worklist, multiple attachments and images may now be pasted from the clipboard. Images will automatically generate an inline image tag.

Signatures

Formatting and images in email signatures

Email signature records may now contain both a plaintext and HTML (Markdown) version. Previously, it was only possible to have formatting in an email signature using an HTML template. Now, when an HTML template doesn’t specify a signature, the signature of the bucket/group is used in the proper format. [#493]

Templates

Improved the email template editor

Improved the email HTML template editor. The tabs for ‘Editor’, ‘Custom Fields’, and ‘Attachments’, have been combined into a single form. Code editors are provided for editing the template and signature.

Drafts

Improved draft editors

When resuming a draft reply:

  • The previously selected group/bucket is now properly set.

  • The previously selected custom fields are now properly set.

  • Custom fields are now properly set to their saved values.

When replying to a message, the option to save a draft is now much more obvious.

Draft formatting in conversations

On ticket profiles, drafts and scheduled messages in the conversation are now displayed with formatting. Previously, drafts were always displayed in plaintext format (sometimes with Markdown). This makes it easier for other workers to review a draft.

Drafts and scheduled messages in the conversation now display the authoring worker’s title. This is consistent with how messages and comments display in recent versions.

Sticky notes on drafts

On ticket profiles, in the conversation timeline, sticky notes may be added to drafts and scheduled messages. For instance, a worker-in-training can ask for feedback before sending a draft. The reviewer can leave an @mention note directly on the draft.

Improved draft previews

When previewing a draft reply in HTML mode, the template now properly adapts to the newly selected group/bucket. Previously, this was always using the template of the parent ticket’s current group/bucket.

When a draft contains HTML formatting it is now displayed on the preview in its peek popup. Previously this always displayed the text version.

On compose/reply drafts, the peek popup now links to the related ticket.

When previewing draft content, #commands are now parsed.

Draft worklists

Draft worklists no longer filter out queued drafts. Workspaces may now include lists of both in-progress and queued drafts. Queue-related fields are now available as columns.

Added new filters to draft worklists for is.queued:, queue.fails:, and queue.deliverAt.

In the workspace page library, the ‘Home’ package now creates a ‘My Drafts’ worklist.

Draft custom fields

Drafts now properly display any custom fields and fieldsets set on them. Previously these were only visible when editing them.

Dashboards

Improved the usability of dashboard widgets

On profile and workspace dashboards, widgets have a new style.

Previously, the widget name heading was a gray rectangle with a shadow. This looked like buttons and made it difficult to visually separate elements.

Now the heading is slightly larger black text on a white background with a light gray bottom border. This helps form controls like buttons really stand out, especially on profile sidebars. A downward-facing arrow to the right of the label makes it more obvious that the widget name can be clicked to reveal a menu. The drag handles are no longer displayed; instead, the mouse cursor changes to the move icon when hovering over a widget header.

Bots

Improved error handling in HTTP requests

In bot behaviors using the ‘Execute HTTP Request’ action, non- 2XX/3XX responses are no longer considered to be errors. For instance, 4XX/5XX responses will still populate and decode the http_response.body placeholder normally. The http_response.error placeholder will only be set for connection-level errors (e.g. invalid host, firewall timeout).

Improved ticket creation from bots

In bots, the ‘Create ticket’ action no longer sends an unexpected outgoing message with an ‘on behalf of’ first message placeholder. This action now creates a new ticket and treats the given message as if it came from an inbound mailbox. No mail is sent. An X-Cerb-Bot header is added to the message with the name of the bot and behavior that created the message.

Form Interactions

Prompt with file upload

Added a ‘Prompt with file upload’ action to form interaction widgets on profiles and workspaces. [#1051]

The prompt can be configured for single or multiple files, which the bot can then validate (e.g. max size, file type). The placeholder contains an array of dictionaries for each uploaded file attachment, each supporting key expansion placeholders (e.g. name, type, size).

Prompt with record chooser

Added a ‘Prompt with record chooser’ action to form interaction widgets on profiles and workspaces. The prompt can be configured for selecting single or multiple records of a given type (e.g. email address, task, worker). A default query and required query can be provided to determine which records are shown in the chooser. The selected records are stored in the placeholder as an array of dictionaries with key expansion. The bot can validate the selected records before continuing.

Search

When using the links: filter in search queries, the deep search can be prefixed with all() to require that all linked records match the given criteria.

Previously, the links filter returned matches where any linked record satisfied the filters.

The all() qualifier simplifies many automations that deal with entire sets (e.g. “all linked time tracking entries are billed”, “all linked tasks are closed”, “all linked approvals are granted”).

For example, this query finds only open tickets records where all linked tasks are completed:


status:open links.task:all(status:closed)

Data Queries

Query GPG key info

Implemented type:gpg.keyinfo data queries. This information isn’t available from worklists.

This requires a fingerprint: argument and returns metadata for the matching key (e.g. subkeys, UIDs, expirations). An optional filter: argument can return only uids or subkeys, suitable for use in sheets.

The new data query type is used by a sheet widget on the new ‘public key’ cards. It could also be used from bots.


type:gpg.keyinfo
fingerprint:A1B2C3D4E5F6
filter:subkeys
format:dictionaries

Query calendar events and recurring events

Implemented type:calendar.events data queries. This returns events and synthesized recurring events for the given calendars grouped into days. The worklist.records data query type isn’t sufficient for this since it doesn’t generate recurring events.


type:calendar.events
calendar:(name:["U.S. Holidays","Office Hours"])
from:"this week Monday 00:00:00"
to:"this week Sunday 23:59:59"
expand:[calendar_owner_]
format:dictionaries

Query classifier predictions

Implemented type:classifier.prediction data queries. This returns a predicted classification for the given text: using the given classifier:. For instance, a ‘Yes/No’ classifier would predict ‘answer.maybe’ for the input “I’m not sure”. [#526]


type:classifier.prediction
classifier:(name:Yes/No)
text:"I am not sure"
format:dictionaries

Sheets

Icons

Icon columns

In sheets, added a new icon: column type. This can display one of the 600+ bundled icons as the image:, image_key: or image_template: parameter. A full list is provided in Setup » Developers » Icon Reference.


- icon:
    key: _icon
    label: Icon
    params:
      image: circle-ok

Icons in card columns

In sheets, card: columns may now specify an icon: parameter to prepend an image to the label. Its values take the same format as a standalone icon: column. The image_template: property can be used to display icons conditionally.



- card:
    key: _label
    label: Label
    params:
      icon:
        image_template: |
          {% if 'closed' == status %}
          circle-ok
          {% elseif 'waiting' == status %}
          stopwatch
          {% endif %}
      bold: true


Icons in text columns

In sheets, text: columns may now specify an icon: parameter to prepend an image to the value. Its values take the same format as a standalone icon: column. The image_template: property can be used to display icons conditionally.



- text:
    key: status
    label: Status
    params:
      icon:
        image_template: |
          {% if 'closed' == status %}
          circle-ok
          {% elseif 'waiting' == status %}
          stopwatch
          {% endif %}


Records

Expand attachments

Data queries and record type dictionaries can use the attachments expansion key to retrieve up to 25 attachments in the same response. The desired number of results can be specified with attachments~{limit}, where limit is any number from 1 to 25 (default 10). The expansion key may be followed by a colon (:) and a comma-separated list of keys to expand on the attachments (e.g. attachments~10:on).


type:worklist.records
of:comment
query:()
expand:["attachments~10:on,custom_"]
format:dictionaries

Expand target records in attachment dictionaries

In attachment dictionaries, the on expansion key returns information about the records the file is linked to. By default expand:[on] returns an array of linked record dictionaries with _context and id keys. The returned record types can be filtered by specifying them like expand:[on.comment,on.message], which returns only information about comments and messages each attachment is linked to (ignoring other types). The returned record dictionaries also support key expansion like expand:["on.message:_label,custom_,ticket_group_"]. Multiple expansion keys are separated with commas. Note that the expansion pattern is double-quoted. [#1011]


type:worklist.records
of:attachment
query:(name:*.png on:comment)
expand:["on.comment:_label,author_,custom_"]
format:dictionaries

Expand comments

Data queries and record type dictionaries can use the comments expansion key to retrieve up to 25 comments in the same response. The desired number of results can be specified with comments~{limit}, where limit is any number from 1 to 25 (default 10). The expansion key may be followed by a colon (:) and a comma-separated list of keys to expand on the comments (e.g. comments~10:author_,target_). [#408] [#1004]


type:worklist.records
of:ticket
query:(status:open)
expand:["comments~5:author_,target_"]
format:dictionaries

Expand custom fields

All record types now consistently support the custom_ expansion key.

Data queries and record type dictionaries can use an improved links expansion key. The links expansion key returns a backwards compatible format. The linked record types can be filtered by specifying them like expand:[links.task,links.contact], which returns only links to tasks and contacts (ignoring other types). The desired number of results can be specified with links.task~{limit}, where limit is any number from 1 to 25 (default 10). The returned record dictionaries also support key expansion like expand:["on.task:_label,comments"]. Multiple expansion keys are separated with commas. Note that the expansion pattern is double-quoted. [#1002]


type:worklist.records
of:ticket
query:(status:o)
expand:["links.project_board_column:_label,board_"]
format:dictionaries


type:worklist.records
of:ticket
query:(status:o)
expand:["links.task~25:_label,comments"]
format:dictionaries

All record types now consistently support the links expansion key.

Expand watchers

All record types now consistently support the watchers expansion key.

Card editor shortcut

When clicking on a card popup link, holding the <Command> or <Shift> key will open the record in edit mode instead. [#433]

Custom Records

Attachments on custom records

Custom records can enable the “Attachments” option to support files being attached to the record.

Comments on custom records

Custom records can enable/disable the “Comments” option. This makes it possible to disable comments on custom records when not desirable. For instance, some parent/child record relationships need to track all comments on the parent (even on child profiles) so they’re visible from every child record or the parent.

Knowledgebase

Improved the knowledgebase article editor

Improved the knowledgebase article editor popup. A code editor with a toolbar is used to edit article content. The article content, attachments, custom fields, and categories, are all managed in a single form now. Previously, these were configured in separate tabs. Articles are now always in Markdown format, although they may still contain HTML tags when necessary.

Security

Stronger password hashes

Upgraded the strength of stored worker password hashes. Previously, this used a custom method (legacy salted SHA1/MD5). Now this uses PHP’s newer password_hash() feature, which will automatically improve over time to use stronger algorithms at higher computational costs. When necessary, worker passwords will be rehashed on the next successful login. [#957]

Performance

Improved performance

  • Improved the performance of the global search menu by caching it per worker. Previously this was reconstructed on every page load based on a worker’s preferences.

  • Optimized key expansion in record dictionaries when using “fuzzy” keys (e.g. custom_, sender_org_). These keys never appear in the dictionary but expand other keys (e.g. sender_org_id, sender_org__label). Subsequent requests of the same fuzzy keys was repeating the expansion. These requests are now properly resolved to keys that exist in the dictionary afterward, and subsequent requests perform no extra work.

  • Improved the performance of most page loads with a cache of record schemas. Previously, on many pages, custom record data was being rebuilt and then sorted into the full list of records. Records were also being extraneously sorted by their plural alias (e.g. tickets) before this step.

  • Improved the performance of most page loads by not sorting page and controller extensions when simply testing for the existence/validity of a single extension.

  • Improved performance when determining which bot behaviors are available for a given event by a given worker. Previously this iterated through every bot to check for events and permissions. In the most common cases, like bot interactions, these behaviors are rare. Now, behaviors of the right type are found first, then permissions are checked and cached per distinct bot.

  • Added database indices to improve the performance of ticket worklist search queries that use the messages.first: and messages.last: filters. Previously, these could result in full table scans.

Platform

Feature deprecations and retirements

  • Retired the plugin library. Most of these repositories were being managed by the official Cerb developers, and the plugins have been moved into the main project. This reduces a lot of extra work during releases. It also resolves issues for teams who run Cerb on an intranet or behind a firewall/proxy. It’s still possible to install third-party plugins in the ./storage/plugins/ directory.

  • Retired the ‘Feedback’ plugin. Existing data is migrated to a ‘Feedback’ custom record.

  • Removed the worker preferences related to mail reply editor sizing (“Automatically grow the text box as I type” and “Set the initial text box height to”). This functionality is automatically handled by the new editor.

  • Retired reply toolbar extensions (cerberusweb.reply.toolbaritem). These are better handled with bot interactions.

  • Retired the deprecated skillset feature. This can be implemented as a ‘record links’ custom field on worker records.

Developers

  • Implemented a .cerbCodeEditorToolbarMarkdown() jQuery plugin for creating reusable toolbars for Markdown editors. This implements tools for: bold, italics, links, lists, images, quoted blocks, code variables/blocks, and tables. Most tools are contextual; they mark up selected text, or insert examples when nothing is selected.

  • Code editors no longer ident subsequent lines when they soft wrap a long line. This functionality can be re-enabled as needed.

Updated dependencies

  • Updated the Ace Editor library from 1.2.6 to 1.4.7.

  • Moved the CssToInlineStyles library to Composer and updated to 2.2.1.

  • Moved the HtmlPurifier library to Composer and updated to 4.11.

  • Moved the Parsedown library to Composer and updated to 1.7.3.

  • Moved the PhpUserAgentParser library to Composer and updated to 0.14.

Miscellaneous Fixes

  • [Localization] Fixed an issue where some database fields weren’t updated to support Emoji in 9.2 because they had an unexpected current encoding. This affected comments, worker titles/locations, and ticket subjects.

  • [Mail/Broadcast] When broadcasting to a ticket worklist, fixed an issue that prevented message previews from working properly.

  • [Mail/Broadcast] When broadcasting to a ticket worklist, it’s no longer necessary to extraneously select a ‘From:’ group. This is now inherited from each ticket.

  • [Tickets/Messages/Custom Fields] Fixed an issue with custom fields set on messages in ticket profiles. Record-level custom fields weren’t displaying on the message in the conversation; only those in a fieldset.

  • [Mail/Sticky Notes] When creating a sticky note, the preview now displays in the note style rather than comment style.