Blog

Release announcements, helpful tips, and community discussion

10.2

Cerb (10.2) is a feature upgrade released on February 23, 2022. It includes more than 186 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 April 30, 2021 then you can upgrade without renewing your license. Cerb Cloud subscribers will be upgraded automatically.

Important Release Notes

Changelog

Added

  • [Metrics] Added a new time-based Metrics service to the platform. [#656]

    Metrics have a unique name like cerb.workers.active and store statistics in multiple resolutions: 5 mins, 1 hour, and 1 day. Samples collected within the same period are aggregated into a statistic set with the number of samples, sum, min value, max value, and average.

    By default, 5 minute samples are retained for 1 day, 1 hour samples for 2 weeks, and daily samples are stored indefinitely.

    A metric is either a counter (increments over time) or a gauge (direct reading of a value at a given time).

    Metrics may be further partitioned with optional key/value pairs called “dimensions”. For example, the cerb.automation.invocations metric has dimensions for the automation and event; which allows for reporting across all automations, specific automations, specific events, or any combination thereof.

    Dimensions may have the following types: extension, number, record, or text.

    Metric samples are buffered until the end of the current request and then are efficiently enqueued for asynchronous processing by a new scheduler job. This means new metric samples may not show up on charts for a few minutes.

    Metrics statistics can be retrieved with data queries.

    These new metrics are managed automatically by Cerb:

    Metric Description
    cerb.automation.duration How long automations are executed. Dimensions: automation_id and trigger.
    cerb.automation.invocations How often automations are executed. Dimensions: automation_id and trigger.
    cerb.behavior.duration How long behaviors are executed. Dimensions: behavior_id and event.
    cerb.behavior.invocations How often behaviors are executed. Dimensions: behavior_id and event.
    cerb.mail.transport.deliveries How many successful messages are sent through a mail transport. Dimensions: transport_id and sender_id (email address).
    cerb.mail.transport.failures How many unsuccessful messages are attempted through a mail transport. Dimensions: transport_id and sender_id (email address).
    cerb.record.search How often each worker searches for a given record type. Dimensions: record_type and worker_id.
    cerb.snippet.uses Snippet usage over time by worker. Dimensions: snippet_id and worker_id. This replaces the snippet_use_history table but imports its data.
    cerb.tickets.open Open ticket counts over time by group and bucket. Dimensions: group_id and bucket_id. The metric is sampled every 15 minutes.
    cerb.tickets.open.elapsed How long tickets spent in the open status by group and bucket. Dimensions: group_id and bucket_id. The metric is sampled when an open ticket is moved to a new group/bucket, or an open ticket transitions to a non-open status.
    cerb.webhook.invocations How often webhooks are executed. Dimensions: webhook_id and client_ip.
    cerb.workers.active Seat usage by workers. Dimensions: worker_id.
  • [UI/Themes/Dark] Added a toggle for dark/light mode in the top right of every page, after the worker name. This instantly switches between themes and updates the worker preference.

  • [UI/Themes/Dark] In dark mode, all HTML-based email messages are now displayed with a darker theme by reducing their colorization. A new ‘Bright mode’ button is available in the message toolbar to view the original colorization on a white background.

  • [Tickets] Added a ‘Last opened at’ field to ticket records. This timestamp is updated when a ticket transitions into the ‘open’ status. For instance, when a new conversation is first opened, or when a ticket re-opens from the ‘waiting’ status. Unlike the ‘Updated’ field, this timestamp is not updated when a ticket is assigned, moved, commented upon, or otherwise modified. Sorting on ‘Last opened at’ in descending order is a more effective way to handle tickets first that have been waiting for the longest.

  • [Tickets/Records/Reporting] On ticket records, added a new ‘Time Spent Open’ field (elapsed_status_open). This contains the total time spent in the open status for each ticket over its lifetime. The total excludes the most recent time elapsed for currently open tickets, which is tracked with the last_opened_at field until the ticket transitions to a non-open status. The sortable ‘Time Spent Open’ column can be added to ticket worklists, and records can be queried with a new filter (e.g. (timeSpentOpen:"> 1 week"). This field is particularly useful for efficient reporting on closed tickets. The ‘time spent open’ broken down by group and bucket is tracked by the cerb.tickets.open.elapsed metric.

  • [Charts/Worklists] Added a set.timezone: filter to worklists. This is used by features like chart widgets to synchronize ‘click-to-search’ results with the timezone of the underlying data query. If timezone data is properly initialized in MySQL, the generated search queries should now match the chart exactly. Otherwise, a timezone offset is used as a fallback; which could be slightly off due to Daylight Savings Time, but is more accurate than not specifying a timezone before. [#1394]

  • [Calendars] On calendars, busy events can now partially block availability. This already happened in availability widgets, but on normal calendars an available event was only hidden if it was completely occulted by one or more busy events. Now busy events partially overlapping an available event will split it into multiple events with different start/end times.

  • [Queues] Added a new Queues service to the platform for distributing units of asynchronous work. Queues are identified with a unique name. Messages with arbitrary payloads can be pushed into a queue. Concurrent consumers can pop messages from the queue to process them. A message is always in one of four states: available, in flight, failed, or complete. For instance, every historical ticket can be reviewed by pushing sets of IDs into a queue as messages. The number of queue consumers can be scaled up to the desired throughput. [#481]

  • [Calendars/Localization] Added a ‘Timezone’ field to Calendar records. This simplifies calendar event inheritance. For instance, a ‘Company Holidays’ calendar with no timezone can define recurring events with patterns like ‘Dec 25’. Worker calendars in various timezones can inherit the company events and generate localized events. Previously, all-day recurring events like Christmas had a specific timezone, which tediously necessitated a separate shared calendar for each timezone. Thanks to 1Password for the feature request.

  • [Profiles/Comments] On profiles, one or more comments can now be pinned to the top of the conversation. This makes it easier to share a summary or todo list for tickets and tasks. Thanks to Advance Local for the feature request. [#1592]

  • [Automations/Metrics] In automations, a new metric.increment: command adds samples to statistics for a metric. This has inputs: for metric_name:, dimensions:, values:, timestamp:, and is_realtime:. All inputs are optional except for metric_name:. By default, samples are queued for efficient background processing. The is_realtime@bool: yes option instantly records the metric at a slight performance penalty. For instance, this is used when generating the global search menu based on recent search activity, since this would be less useful to have delayed by several minutes.

  • [Automations/Queues] In automations, added queue.push: and queue.pop: commands for adding and processing messages in queues.

  • [Automations] In automations, a new file.read: command can read chunks of bytes from an attachment or automation resource. For inputs:, the resource is provided as a uri: and the starting byte is offset:, with an optional length:. This allows automations to process large attachments without exhausting memory. The output: is a dictionary with keys: bytes, uri, name, offset_from, offset_to, mime_type, and size. If bytes contains binary it is base64-encoded and returned as a data: URI string. The command enables many new workflows, like automatically processing DMARC reports, bounces, iCal/ICS invites, etc. [#152] [#766] [#1477]

  • [Data Queries/Attachments] Added a new attachment.manifest data query type. This iterates and filters the manifest of attachment archives (e.g. ZIP). This can be combined with file.read: in automations to extract specific files from an archive.

  • [Metrics/Data Queries] Added a new metrics.timeseries type to data queries for fetching metric statistics over a date range. This can retrieve multiple series each with a different metric and function (avg, sum, min, max, count). A series can also be aggregated or filtered by any combination of metric dimensions.

  • [Portals/Interactions] In website interaction portals, say: form elements can specify references: to generate secure URLs for ‘portal image’ resource records. Each references:resource:uri: should point to a cerb:resource:{name}. The resource/name: should be used in place of the URL as a fragment. For instance, references:resource/logo: would generate the URL for ![Logo](#logo). This format will generate a secure (signed) URL for the image request that doesn’t require external hosts.

  • [Portals/Interactions] In website interaction portals, the layout can now be customized. This includes a logo image, logo text, page title, favicon, navigation links, and the floating badge interaction. The layout is defined in KATA when configuring the portal. Logo and favicon images are provided as URIs to resource records.

  • [Portals/Interactions] On website interaction portals with a say: form element, inline Markdown images can contain a preferred width and height. Images are specified like ![Alt](url). To specify a width and/or height, use ![Alt =500x500](url), where the numbers after the space and equals are the width and height. The width or height can be omitted, like 500x or x500.

  • [Portals/Interactions] On website interaction portals with a say: form element, links can be relative and will be rewritten using the full URL and path prefix. This is useful when custom domain names and paths aren’t knowable in advance. For instance, [label](/path) might link to https://example.com/prefix/path depending on the portal configuration.

  • [Portals/Interactions] Website interaction portals can directly serve ‘portal image’ resource records from the /assets/image/ endpoint. For simple use cases, this removes the need for an external content delivery network (CDN) to store image content. A Content-Security-Policy: only needs to allow the portal host. Generated URLs for image requests are signed with a secret key to ensure only the resourced used by the portal are accessible. This secret can be configured and rotated from security:imageRequests:secret: in the portal schema.

  • [Resources/Images] Added a new ‘Image’ resource type for logos, icons, and other artwork in the worker interface. This supports PNG, JPEG, GIF, and SVG images. SVG images are sanitized.

  • [Search/Interactions/Toolbars/Usability] Added a new global.search toolbar that adds interactions to the global search menu in the top right of every page. The most recently searched record types per worker are now automatically added to the menu as shortcuts. The existing ‘record type’ search favorites (from worker settings) are always pinned to the menu as shortcuts. The ‘show all record types’ menu item is now an interaction with a searchable list.

  • [UI/Logo] SVG images can now be used for the UI logo.

  • [UI/Styles/Dark] In Setup->Branding, separate logos may be uploaded for light mode and dark mode. Logo images are now stored as ‘Resource’ records rather than in the storage filesystem. The 10.2 update will convert existing logos to a resource. The default Cerb logos now use SVG sources for sharper display on high-resolution screens.

  • [Automations/Attachments] In automations, the file.read: command has a new extract: option for extracting an individual file from a ZIP archive. This is used in conjunction with the new attachment.manifest data query type that lists the contents of an archive.

  • [Automations/Events/Mail] Added the mail.reply.validate automation event. This enables interactive validators when a worker starts replying to a message on a ticket. Validations are interactions that can optionally abort the reply before a draft is created. If not aborted, the reply editor opens like normal. For instance, this can detect a duplication of effort when another worker starts a reply between the time the current worker viewed the ticket and started replying. This feature was previously built-in, but is now fully customizable as an automation. [#1500] [#1529]

  • [Automations/Events/Records] Added the record.profile.viewed automation event. This can trigger actions when a worker views a record profile. For instance, metrics on ticket profile views. [#1550]

  • [Automations/Events] Added a new worker.authenticate.failed automation event that triggers after a worker fails to authenticate a new session. This receives inputs for the worker_* record, client_ip, client_browser_name, client_browser_version, and client_browser_platform.

  • [Automations/Events] Added a new worker.authenticated automation event that triggers after a worker successfully authenticates a new session. This receives inputs for the worker_* record, client_ip, client_browser_name, client_browser_version, and client_browser_platform. If an automation returns a deny: key, the login is denied with a custom error message. This event enables new workflows like: security audits on new sessions (compare historical browser, IP, location), worker browser metrics, deny old browser versions, IP-based firewalls per worker, etc.

  • [Automations/Usability] When creating a new automation in the editor, new default content for the script and policy offers helpful tips about what to do next.

  • [Dashboards/Time Blocks] Added a new ‘Chart: Time Blocks’ card widget for visualizing the intensity of hourly coverage over a range of days. This uses a data query (usually calendar.availability) with format:timeblocks. For instance, aggregating the availability calendars of a group’s members to display shift coverage for the current month.

  • [Dashboards/Time Blocks] Added a new ‘Chart: Time Blocks’ profile widget for visualizing the intensity of hourly coverage over a range of days.

  • [Dashboards/Time Blocks] Added a new ‘Chart: Time Blocks’ workspace widget for visualizing the intensity of hourly coverage over a range of days.

  • [Resources/Portals] Added a new ‘Portal Image’ resource type for logos, icons, and artwork in portals. This improves security by avoiding using attachment records for this purpose.

  • [Automations/Logs] In Setup » Developers, a new Automation Logs page allows administrators to view and purge logs from all automations in one place. Thanks to @mryanb for the request!

  • [Automations/Resources] Added Automation Resource records for efficient handling of large binary objects within automations. For instance, the http.request command can stream a GET request for a large video download directly into a temporary resource file and return its Cerb record URI rather than 100MB of bytes. This also protects the privacy of files that are uploaded in automations (e.g. interactions) which should never be treated like attachments.

  • [Behaviors/Automations] In bot behaviors, added a new ‘Execute automation’ action which passes inputs to a behavior.action automation and returns the results. This helps with the gradual transition from behaviors to automations, and enables behaviors to use all the functionality from automations. Thanks to 1Password for the feature request!

  • [Data Queries/Availability] Added a new calendar.availability data query type. This aggregates any number of matching calenders to display availability over a date range by hour or day. For instance, this can be used to visualize when a group is most or least available for shift planning. The output formats are dictionaries and timeblocks. Thanks to 1Password for the feature request.

  • [Mail/Commands] When composing, replying, or relaying email, added a new #start note command for adding a multi-line sticky note to the message once created. The note can be any number of lines following the command until an #end command on its own line.

  • [Mail/Drafts/Commands] Implemented the #start comment command for multiple line comments in drafts for compose and replies.

  • [Metrics/Dimensions] In metrics, added a number type to dimensions. This efficiently stores a positive whole number.

  • [Automations/Metrics] In the automation builder, added a helper interaction for the metric.increment: command. This automatically defaults the available dimension key/values.

  • [Automations/Reminders] Added a reference cerb.reminder.remind.email automation for the reminder.remind automation event. This sends reminders by email to the target worker.

  • [Data Queries/Metrics] In metrics.timeseries data queries, added the ability to aggregate results in period: by week, month, and year. Previously this only supported: minute, hour, and day.

  • [Data Queries/Metrics] On metrics.timeseries data queries, a new series.*:missing: key configures what to do with missing samples at a time interval. The options are null (default), zero (set to 0), or carry (carry the last sample).

  • [Data Queries] Added a new autocomplete.completions data query that returns autocompletion suggestions data for a given automation key path. This can be used by functionality like interactions to inspect an automation at the current cursor to offer contextual suggestions.

  • [Data Queries] Added a new data.query.types data query that returns metadata about the available types (name, description, etc). This can be used by functionality like interactions to assist in data query generation.

  • [Data Queries] Added a new platform.extension.points data query type for filtering and paging through a list of platform extension points.

  • [Debug] In the /debug/status endpoint, a new scheduler section shows stats for all scheduler jobs, including the last run time. This simplifies monitoring and alerts.

  • [Records/Search/Calendars] On calendar records, added a workerAvailability: search filter. This matches calendars configured for worker availability (opposed to calendars owned by workers).

  • [Records/Search] On draft worklists, added a ticket.id: filter.

  • [Toolbars] In toolbars, divider: items draw a horizontal divider between menu item sections.

  • [Tickets/Worklists] On ticket worklists, added a new icon to the top right which automatically scrolls to the actions toolbar below the list. This removes the need to scroll down when working with long work pages (e.g. 50+ items). Thanks to NJ Advance Media for the feature request.

  • [Dates] Added new date range shortcuts in data queries and search filters for: this year, last year, and next year.

  • [Automations] In automations, added log.warn: and log.error: actions. These are aliases for log: but set the severity for filtering. The default severity of log: is debug.

Changed

  • [Data Queries/Worklists/Subtotals] On worklist.subtotals data queries, the timezone: option must now be a location (e.g. America/Los_Angeles) rather than an offset (e.g. -08:00). This makes it possible to localize data queries for each worker by using their timezone placeholder. An invalid timezone returns an error, and if omitted it defaults to the timezone of the current worker (if there is one). This removes the need to specify a timezone or offset in the date range, as any date-based filters and date-based groupings are now synchronized automatically.

  • [Data Queries/Worklists/Series] On worklist.series data queries, added the timezone: option. This takes a location like America/Toronto or Europe/Berlin. If omitted, it defaults to the timezone of the current worker, or the server if there’s no worker session.

  • [Calendars/Recurring] Fixed an issue in calendars with recurring events that spanned multiple days. For instance, if a worker had an overnight shift from 6p-2a (18:00-02:00), the event wasn’t displaying unless the end time was tomorrow 2am. Now, end times with earlier hours than start times are assumed to be the next day. Multiple day recurring events patterns now generate separate events for each day. This already happened for non-recurring events. Thanks to 1Password for the report. [#1601]

  • [Calendars] On calendars, event start and end times (when visible) are now displayed to the right of the name. Times are not shown for all-day events like holidays.

  • [Search/Fulltext/Performance] When running a fulltext search, Cerb will now first check the total hit count for the given terms. If less than a lower threshold (default 1,000) the results will be returned as IDs rather than an IN(...) join. This reduces index contention in complex queries. The threshold can be configured with the APP_OPT_FULLTEXT_THRESHOLD_IDS constant.

  • [Search/Fulltext/Performance] When running a fulltext search, Cerb will now first check the total hit count for the given terms. If greater than the upper threshold (default 10,000) the results will be joined using EXISTS rather than IN. The EXISTS strategy is faster when there are fewer matches for non-fulltext filters than fulltext (e.g. searching a date range or a particular org’s history). The IN strategy is usually faster when there are fewer matches for fulltext filters than non-fulltext (e.g. searching all historical tickets for an uncommon phrase). The threshold can be configured with the APP_OPT_FULLTEXT_THRESHOLD_EXISTS constant.

  • [Automations] Automations now have an execution time limit (default 25s) rather than an operation limit. This still prevents infinite loops without inconsistently prohibiting functionality. The time limit can be override from the automation policy with the settings:time_limit_ms: key.

  • [Project Boards/Performance] Project boards now load up to 100 cards per column by default. Additional cards can be loaded with a ‘show more’ link at the bottom. This improves performance on heavily used boards; particularly in the ‘Completed’ column. One noteworthy client had over 23,000 completed cards and was experiencing memory issues while rendering the column.

  • [Automations] The cerb.data.records (ui.sheet.data) automation now accepts a query: input (rather than required_query:) and a query_params: input for untrusted query placeholder substitution.

  • [Profiles/Performance] Profile tabs are now properly loaded from the cache rather than the database.

  • [Profiles/Performance] Profile widget configurations are now cached per profile tab, rather than loaded from the database on every request. The cache is properly invalidated on widget edits as well as reordering.

  • [Profiles/Tickets/Performance] Optimized database queries when loading ticket profiles: requesters, senders, workers, contacts, orgs, custom fields, headers, files, and toolbars. More data is bulk loaded in fewer queries, and previously loaded records are reused when possible.

  • [Automations/HTTP] In automations, the http.request action can now directly stream large attachment/resource uploads for PUT and POST HTTP requests. Set the Content-Type: header to application/vnd.cerb.uri and set the HTTP body to a record URI like cerb:attachment:123. The automation will take care of streaming the bytes to the HTTP endpoint, which avoids memory issues with loading large attachment content into an automation variable.

  • [Automations] In automations, when using the http.request command, a large HTTP response body (>1MB) will now be returned as an automation resource record for further processing. These bytes are streamed directly to a file to avoid memory limitations in the automation (e.g. video processing). When this occurs, output:is_cerb_uri: is true, the output:content_type: key is replaced with application/vnd.cerb.uri, output:content_type_original: contains the original content type, and the HTTP body is a Cerb record URI (e.g. cerb:automation_resource:c10028f0-1cad-11ec-81e5-59d4c4af2d7). The new file.read: command can be used to process the file in chunks.

  • [Automations] In automations, when using the http.request command, a binary HTTP response body is now automatically converted to a base64-encoded data: URI. This resolves issues with serializing automation states containing unprintable characters (e.g. simulation). You should always use the http.request:on_success: handler to verify an HTTP response. When this occurs, the output:is_data_uri: is true.

  • [Platform/Cache/Performance] When using Memcached for the cache service, consistent hashing is now enabled by default. When using a cluster that adds or removes nodes, consistent hashing reduces the number of keys that are rebalanced.

  • [UI/Styles/Themes] In the stylesheet, separated the colors (themes) from layout and condensed styles. This makes it easier to create alternative color schemes – like dark mode. [#1281]

  • [Mail/Routing/Automations] Automations on the mail.route event can now route directly to a specific bucket rather than just to a group inbox.

  • [Cards/Widgets] Time-series chart widgets can now be added to cards.

  • [Sheets] On sheets, selection: columns may now specify an optional params:label:, params:label_key:, or params:label_template:. This displays a text label next to the checkbox or radio button; avoiding the need for an extra column.

  • [Data Queries/Record Types] On record.types data queries, a new options: filter returns record types with one or more matching options: autocomplete, avatars, cards, comments, custom_fields, links, owner, records, search, snippets, va_variable, watchers, workspace

  • [Snippets/Bulk] In snippet worklists, bulk update can now delete multiple records. [#1282]

  • [Custom Records/Bulk] On custom record worklists, bulk update can now delete multiple records at once. [#1512]

  • [Mail/Parser] When threading inbound messages to existing conversations, the In-Reply-To: header is now prioritized, and all References: message-ids are checked in reverse order. This should resolve issues where a ticket is split, but replies to the split messages still thread to the original conversation.

  • [Interactions/Sheets] In interactions using a form:await: continuation with a sheet: element, an __index key is now synthesized in the data: dictionaries. This is the index of the dictionary in the collection, which is often not otherwise available as a dictionary value. In many cases this would be a zero-based ordinal position. For instance, this allows a sheet: element to return the index of a dictionary, from which any key can be loaded by later logic.

  • [Sheets/Grid] In sheets, the layout: grid style has been significantly improved. The grid no longer shows checkboxes on each item for selection. Instead, the entire cell is toggled on and off by clicking anywhere in it. Cells use flexbox for arrangement, and sheet columns are displayed from top-to-bottom; allowing for enhancements like icons and descriptions. This makes it easier to show many options in a smaller space while retaining readability.

  • [Interactions/Editor] In interaction.worker automations, with an await:form: continuation, editor: form elements with a syntax: option will now properly control syntax highlighting and autocompletion in the editor. For instance, syntax: data_query will highlight and autocomplete data query syntax.

  • [Automations/Editor/Usability] In the automation editor, improved autocompletion for values on the same line as their key (e.g. key: value). [#1476]

  • [Automations/Editor/Usability] In the automation editor, the value for uri: keys now autocompletes in commands.

  • [Automations/Editor/Usability] In the automation editor, the possible keys for inputs: are now autocomplete suggestions in the function: command.

  • [Automations/Editor/Usability] In the automation editor, the possible values for record_type: are now autocomplete suggestions in record.*: commands.

  • [Automations/Editor/Usability] In the automation editor, the possible keys for fields: are now autocomplete suggestions in record.*: commands.

  • [Automations/Editor/Usability] In the automation editor, the possible values for metric_name: are now autocomplete suggestions for metric.*: commands.

  • [Automations/Editor/Usability] In the automation editor, the possible keys for dimensions: are now autocomplete suggestions for metric.*: commands.

  • [Automations/Editor/Usability] In the automation editor, the possible values for queue_name: are now autocomplete suggestions for queue.*: commands.

  • [Automations/Editor/Usability] In the automation editor toolbar, the “add” menu button has been replaced with a “magic” interaction that provides contextual suggestions based on the current cursor position in the code. These suggestions may also launch helper interactions to build syntax.

  • [Automations/Editor/Usability] In the automation editor, improved the helper interaction for building data.query: commands.

  • [Automations/Editor/Usability] In the automation editor, improved the helper interaction for building http.request commands.

  • [Automations/Editor/Usability] In the automation editor, possible values for icon: are now autocomplete suggestions in sheet: and submit: elements for await:form: continuations.

  • [Automations/Editor/Usability] In the automation editor, autocomplete suggestions are now ranked so the most common options are recommended first.

  • [Automations/Editor/Usability] In the automation editor, autocomplete suggestions now include descriptions.

  • [Automations/Editor/Usability] In the automation editor, autocomplete suggestions insert more complete code templates.

  • [Automations/Editor/Usability] In the automation policy editor, added an autocomplete suggestion for deny/type: to the data.query: command.

  • [Toolbars/Autocomplete] In the toolbar editor, possible values for uri: are now autocomplete suggestions in interaction: commands.

  • [Toolbars/Autocomplete] In the toolbar editor, possible values for icon: are now autocomplete suggestions in interaction: commands.

  • [Toolbars/Autocomplete] In the toolbar editor, possible keys for inputs: are now autocomplete suggestions in interaction: commands.

  • [Calendars] On calendars, ‘Easter’ is now a valid pattern for recurring events. Alone it will be evaluated as Easter day in the current year and timezone. It may also be used relatively, like “Easter -7 weeks Wednesday” and “Easter +3 days”. Thanks to 1Password for the request! [#1535]

  • [Automations/Interactions/Sheets] In interactions, sheet: prompts now automatically continue when they’re in single selection mode and the only prompt. The continue button should be hidden to avoid requiring two clicks.

  • [Interactions/Sheets] In worker interactions, sheet: prompts have a new columns layout style that renders sheet items from top to bottom in a columns. Columns start from the left and responsively add/reduce based on the popup width. This is similar to the grid layout which arranges items in rows from left to right, top to bottom.

  • [Automations/Editor/Usability] In the automation editor, the helper for the record.create: command now automatically selects all of a record type’s required fields by default. Previously this had to be done manually.

  • [Automations/Events] In the automation event editor, the interaction:uri: key now autocompletes with only suggestions from the current event trigger. Suggestions are also provided for interaction:inputs:.

  • [Automation/Events/Usability] In the automation event editor, the (+) toolbar item now starts the interaction in a single click. Previously this showed a one item menu and required an extra click.

  • [Automation/Events] In the automation event editor, the (+) interaction now warns on invalid cursor placement. New automations can only be added at the top-level of the KATA script (no indentation).

  • [Portals/Interactions] interaction.website automations can now return:redirect_url: to redirect the portal visitor to a URL. For instance, after completing a survey the visitor can be redirected back to the project website or support portal.

  • [Sheets/UI] In sheets using layout:style:grid, a layout:params:width: option determines the width of grid cells. The default is auto where each cell can be a different width.

  • [Portals/Interactions] In Website Interactions’ portals, it’s now possible to disable the floating icon when viewing the portal directly (rather than embedding on a website).

  • [Resources] Resource records may now store additional parameters based on their type. For instance, after validation, an ‘image’ resource can store the width, height, and MIME type.

  • [Portals] When saving a portal configuration, the ‘updated’ timestamp is now updated on its record.

  • [Records/Snippets] When editing snippet records, prompted placeholders now provide autocomplete suggestions.

  • [Portals/Interactions] When configuring website interaction portals, a copy/paste code snippet is provided for including an interaction widget on your website. Previously this syntax was buried in the documentation.

  • [Portals/Interactions] In website interaction portals, interactions open in wide mode when viewing the portal directly (rather than the widget on a third-party website).

  • [Portals/Interactions] In website interaction portals, styles are more easily configurable from third-party website stylesheets using CSS --var variables.

  • [Records/Usability] All record editors now support the warning when closing the popup before saving.

  • [Records/Automations] Automation worklists can now display rows on two lines if the ‘Name’ column is omitted. The name is shown on its own line and the second row has more room for extra columns.

  • [Portals/Website Interactions/Mobile] On website interaction portals, improved responsiveness for mobile devices. When a popup is very tall it will now scroll rather than disappearing out of the viewport.

  • [Resources/Portals] Resource records of the ‘Portal image’ type may now include the SVG format (vector).

  • [Records/Watchers/Performance] In the record watchers popup, added a cache for worker responsibilities and workloads to improve performance on large teams.

  • [Automations] When editing automation records, the cerb. namespace is reserved. These automations are managed automatically and shouldn’t be edited directly.

  • [Records/Tickets] On the ticket record editor popup, a Shift+Enter keyboard shortcut automatically focuses the ‘Save Changes’ button. Thanks to Kent at Flexibits for the feature request. [#1593]

  • [Records/Search] In record search queries, date-based filters can now use date range shortcuts like this week, last week, last month, last year, today, yesterday, and tomorrow.

  • [Records/Search] Fixed an issue with header.*: filters on message record search queries. These weren’t filtering by the header_name attribute, which could return inflated counts and use a less efficient join strategy. For instance, using header.deliveredTo:sales@cerb.example would count hits in all headers and not just delivered-to. The final results were accurate, but the aggregation could time out.

  • [Resources] When editing resource records, the cerb. namespace is reserved. These resources are managed automatically and shouldn’t be edited directly.

  • [Automations/HTTP] In automations, the http.request: command now returns a full HTTP response in the on_error: event. This includes status_code, content_type, headers, and body. Previously, only a truncated error message was available. [[#1605](https://github.com/jstanden/cerb/issues/1605]

  • [Calendars/Localization] Recurring calendar events are no longer required to specify a timezone. Instead, a new “(use calendar timezone)” option may be selected. This allows ‘all-day’ recurring events (e.g. Christmas) to be shared properly between calendars in different timezones.

  • [Mail/Relay] Bot behaviors that use the ‘Send email relay to workers’ action will no longer relay to disabled workers.

  • [Calendars] On calendars, all-day events no longer show a start time.

  • [Platform/Dependencies] Updated the Twig templating engine from 3.1.1 to 3.3.8. This improves PHP 8.1 support.

  • [Platform/Dependencies] Updated the Smarty templating engine from 3.1.44 to 4.1.0. This improves PHP 8.1 support.

Deprecated

  • [Platform] The upcoming Cerb 10.3 update will require PHP 8.0+ and MySQL 5.7+.

  • [Platform/Search] Sphinx search engine support will be removed in Cerb 10.3.

  • [Bots/Behaviors] Bot behaviors should continue to migrate to automations.

  • [Tickets/Comments] On ticket profiles, with the “Conversation” widget, the “Pin the last comment to the top of the conversation” will be removed in a future update. Use the new “pin” feature directly on comments.

Removed

  • [Profiles/Ticket/Usability] On ticket profiles, removed the attachments search button from the top right when hovering over a message. This can be reimplemented as an interaction on the mail.read toolbar. We had reports of the attachments and permalink buttons being confused for each other. [#1547]

Fixed

  • [Platform/PHP] Compatibility with PHP 8.0 and 8.1.

  • [Records/Custom Fields] Fixed an issue in record dictionaries when expanding the customfields key. This didn’t write a value to customfields in the dictionary, so subsequent requests could re-load fields and duplicate values for some types (e.g. record links).

  • [Interactions/Sheets] Fixed an issue with worker interactions with sheet prompts. If single selection is enabled, de-selecting a row still keeps its value until another option is selected. This meant someone could ‘Continue’ after de-selecting an option without selecting something else.

  • [Records/Custom Fields] When creating or updating records, URL-based fields now automatically truncate when over 255 characters in length. Previously these fields returned a validation error.

  • [Automations/Validation] Fixed an issue with validation on some automation commands (e.g. var.set:) where values didn’t allow pure numbers.

  • [Data Queries/Records] In record.fields data queries, fixed an issue with the worker record type where keys weren’t returned for email,email_ids, and password.

  • [Interactions/Website] Fixed an issue with interaction.website automations when selecting sheet: items with the keyboard rather than the mouse.

  • [Dashboards/Maps] On profiles and dashboards, fixed an issue with ‘Map’ widgets where the Maps KATA was inserted in the wrong editor.

  • [Automations/Data Queries] Fixed an issue with data query query_params: dynamic bindings. Dynamic text values are now always enclosed in quotes. This affected functionality that converts tokens back to queries, where the values weren’t properly escaped.

  • [Automations/Continuations] Added a maintenance cleanup task for automation continuations.

  • [Tickets/Mail] Fixed an issue with the ‘Expand quoted text’ option on plaintext email. A quoted block wasn’t collapsed if it started on the first line of the email. This isn’t common since most mail applications add a header line like, “At date/time, someone wrote:”.

  • [Data Queries/Worklists] Fixed an issue with data queries that can specify a query: with filters. Nested booleans weren’t parsed properly (e.g. (a OR (b AND c)).

  • [Tickets/Cards/Usability] Fixed an issue when replying to a ticket from its card when scrolled down a page (e.g. replying to a long message body). When the reply was sent, the ticket card was still positioned far down the page, rather than at the top where it was expected. Thanks to @mryanb for the report!

  • [Mail/POP3] Fixed an issue with POP3 mailboxes when downloading messages that used an unsupported encoding in the envelope headers. This could prevent new mail from downloading as the message repeatedly failed on each attempt. The issue was in the Horde IMAP library, but is mitigated by returning the raw headers and parsing them ourselves. The situation is only required when a message is larger than the mailbox limit. Thanks to PassMark Software for reporting!

  • [Mail/Parser] Fixed an issue with the email parser when a message specified an unsupported encoding on the plaintext part. This caused the message to fail and temporarily blocked the scheduler job from parsing other email (for about 10 mins). The encoding wasn’t being checked before testing if the current message contained an inline bounce message (which is converted to an attachment). If the encoding fails, the bounce test is now skipped and processing continues normally.

  • [Interactions/Sheets/Toolbars] Fixed an issue when rending toolbars on sheets prompts in worker interactions. The Toolbar KATA didn’t have access to all placeholders in the automation state, which made it difficult or impossible to conditionally enable/disable toolbar items based on anything other than selected rows. Thanks to Corey at 1Password for discovering and reporting the issue.

  • [Calendars/Sync] In calendars, fixed an issue where a calendar could synchronize with itself. This caused calendar operations to time out. Thanks to 1Password for discovering and reporting the issue.

  • [Platform/Installer] The requirements checker now ensures the mysqlnd PHP extension is enabled. This is required for asynchronous queries, parallel queries, and query timeouts.

  • [Mail/Localization] Fixed an issue in the email parser when generating a plaintext part from an HTML-only message. If the HTML part included a content-type in the meta header, non 7-bit characters were corrupted (e.g. accents, emoji, multibyte). Thanks to @ScreamBE for reporting. [#1597]

  • [Mail/Parser] Fixed an issue in the email parsing when generating a plaintext part from HTML. Non-breaking spaces could be left in the plaintext. These are now ignored.

  • [Behaviors/Custom Fields] Fixed an issue on the ‘Create’ actions in behaviors (e.g. ‘Create task’) when setting custom fieldsets.

  • [Mail] Fixed an issue when sending mail with a custom ‘From:’ header.

  • [Worklists/Bulk] Fixed an issue with bulk updating multiple checkbox custom fields on worklists. [#1526] [#1556]

  • [Tickets/UI] On HTML messages and comments, fixed an issue with improper aspect ratios when responsively scaling images. The maximum width was being enforced, but this could stretch the height.

  • [Addresses/Merge] Fixed an issue when merging email addresses when the Support Center plugin has never been enabled. These database tables are now ignored if they don’t exist.

  • [Automations/Inputs] Fixed an issue with automations where trailing whitespace in inputs:record:record_type: would return an ‘invalid record’ error for valid record IDs. Thanks to ChargeOver for the bug report.

  • [Automations/Mail/Filtering] Fixed an issue with mail.filter automations where the return:set:email_subject: key wouldn’t re-thread the inbound message if a ticket mask was added or removed in the subject line. Thanks to Corey at 1Password for discovering the bug.

  • [Dashboards/Prompts] Fixed an issue with dashboard ‘chooser’ prompts. If the default: value was provided as an array it could prevent the dashboard from rendering. Thanks to Corey at 1Password for discovering the issue.

  • [Widgets/Charts] Fixed an issue on card, profile, and workspace chart widgets. If the y-axis was formatted as time elapsed (seconds or minutes), but provided as a float (e.g. 65.5) then the human-readable date included the text undefined, like 1m,5undefined5s.

  • [Records/Dates] Fixed an issue in record editors with a date field. It’s now possible to input relative times like +1h and -2hr. Previously these failed unless a space was provided between the count and the unit. Thanks to 1Password for the report.

  • [Automations/Records] Fixed an issue in automations with the record.upsert action. The fields: dictionary had its placeholders evaluated twice – once by record.upsert and a second time by either record.create or record.update. This led to unexpected results when a placeholder value contained characters that were interpreted as another placeholder (like {{). Thanks to @mryanb for reporting the issue.

  • [Automations/HTTP] In automations, fixed an issue with the http.request: command when setting the body: as a dictionary and using a Content-Type header. The header name is no longer case-sensitive, and attributes like charset are ignored when matching. [#1606]

  • [Reports/Time Tracking] Fixed an issue on the example ‘Time Spent By’ reports. These reports are now properly based on seconds rather than minutes.

  • [Records/Search] Fixed a browser warning about ‘showLineNumbers’ being an invalid option when opening a search popup.

  • [Workspaces/Usability] Fixed an issue on workspace dashboards where a widget would disappear if it failed to load.

  • [Automation/Scripting] Fixed the missing array_count_values() scripting function in code editor autocompletion suggestions.

Security

  • [Security] Worker default passwords are created in the new password_hash format. Previously this used the old salt+SHA1 format and was automatically upgraded after the first login.

  • [Tickets/Security] Added additional role permission checks when workers delete tickets from worklists or profile pages.

  • [Automations/Scripting/Security] In automation scripting, the |markdown_to_html(is_untrusted=true) filter now uses ‘untrusted’ mode by default to allow Markdown formatting escape HTML tags. The optional argument can allow HTML tags for trusted input in special cases.

  • [Portals/Interactions/Security] Website interaction portals now include the nonce attribute on script tags. This makes it easier to implement a strict Content-Security-Policy.

  • [Portals/Interactions/Security] On website interaction portals, the direct pages now use a strict Content-Security-Policy.

  • [Portals/Interactions/Security] In website interaction portals, when using the direct page link, the Content-Security-Policy: header img-src directive can be configured with security:contentSecurityPolicy:imageHosts@list:. This allows external images to be used in interactions from trusted hosts.

  • [Dashboards/Widgets/Security] On cards, profiles, and workspaces, ‘Time Series’ widgets may now use the ${placeholder} syntax in data queries for untrusted user input.