Collaboration
Keep your team in sync with built-in comments and status updates. No more scattered communication across multiple tools.
Installation
Add gem: Add the following to your Gemfile:
rubygem "avo-collaborate", source: "https://packager.dev/avo-hq"
Bundle: Run bundle install:
bashbundle
Install migrations: Generate the required database migrations:
bashrails avo_collaborate:install:migrations
Run migrations: Apply the migrations to your database:
bashrails db:migrate
Configure resources: Enable collaboration on your resources by adding
self.collaboration
to your resource configuration.Add timeline: Include the collaboration timeline in your resource using
collaboration_timeline
.Configure permissions: Add the required authorization methods to your resource policies.
-> self.collaboration
Configure collaboration settings for your resource. This hash contains author and watchers configuration.
# app/avo/resources/project.rb
class Avo::Resources::Project < Avo::BaseResource
self.collaboration = {
author: {
current_author: -> { current_user },
name_property: :name,
},
watchers: [
{
property: :name,
message: -> { "This property has been updated #{property}: #{old_value} -> #{new_value}" }
},
{
property: :status,
i18n_message_key: "avo.collaboration.custom_property_changed_html",
},
{
property: :stage,
}
]
}
def fields
# ...
end
end
author
current_author
: A lambda that returns the current user/author objectname_property
: The property on the author object that contains their display name
watchers
Watchers monitor changes to specific properties and can generate automatic timeline entries when those properties change.
Each watcher can have:
property
: The property name to watch for changes (required)message
: A lambda that generates a custom message when the property changes. Available variables:property
,old_value
,new_value
i18n_message_key
: An internationalization key for the message instead of a custom lambda
If neither message
nor i18n_message_key
is provided, a default message will be generated.
I18n Example
When using i18n_message_key
, define your translations in your locale files:
en:
hello: "Hello world"
avo:
collaboration:
custom_property_changed_html: changed %{property} to %{new_value} <span class="font-bold">[Custom]</span>
The message can use interpolation variables like %{property}
, %{old_value}
, and %{new_value}
.
Safe HTML Translations
When your translation messages contain HTML markup (as shown in the example above), Rails automatically treats them as safe HTML when the translation key ends with _html
. This follows Rails' safe HTML translations convention, allowing you to include styling and formatting in your collaboration timeline messages without additional escaping.
-> collaboration_timeline
The collaboration_timeline
method renders the collaboration timeline component at the specific position where it's defined within your resource's fields.
# app/avo/resources/project.rb
class Avo::Resources::Project < Avo::BaseResource
self.collaboration = {
# ...
}
def fields
field :id, as: :id
field :name
field :status
field :stage, as: :select, options: ["Not Started", "In Progress", "Completed"]
collaboration_timeline
end
end
This DSL method will display the collaboration timeline (showing comments, status updates, and property changes) wherever you place it in your resource definition. You can position it among your other fields to control where the timeline appears in your resource's layout.
Customizing collaboration models for your business logic
Sometimes, the default collaboration models aren't quite enough for your specific use case. You might want to add custom associations, validations, or callbacks to align with your application's domain logic.
You can safely extend Avo::Collaborate::Action
, Avo::Collaborate::Comment
, and Avo::Collaborate::Entry
in an initializer, similar to how you would extend other Avo provided models:
# config/initializers/avo.rb
Avo.configure do |config|
# ... other config options ...
end
Rails.configuration.to_prepare do
# For actions generated by watchers (property changes, status updates, etc.)
Avo::Collaborate::Action.class_eval do
after_create :slack_notification
private
def slack_notification
SlackNotificationService.notify(message: "New action created: #{body}")
end
end
# For user-authored comments in the collaboration timeline
Avo::Collaborate::Comment.class_eval do
validates :body, presence: true, length: { maximum: 5000 }
before_validation :sanitize_body
private
def sanitize_body
self.body = HtmlSanitizer.sanitize(body)
end
end
# Wrapper entry that unifies both comments and actions via delegated_type :entryable
Avo::Collaborate::Entry.class_eval do
after_create :discord_notification
private
def discord_notification
DiscordNotificationService.notify(message: "New action created: #{body}")
end
end
end
This approach lets you integrate collaboration events with your domain models while keeping the core Avo functionality intact. Add only the associations and callbacks that make sense for your application.