Make a dismissible only alert component
Create a reusable DismissibleAlertComponent for consistent callout testing
Background & Context
This follow-up issue was created from a discussion in MR !191338, which implemented dismissible alerts for GitLab Duo with Amazon Q trial notifications. During the review, @dstull suggested creating a standardized DismissibleAlertComponent to reduce the testing burden for dismissible callouts across the application.
Currently, each dismissible alert implementation requires its own feature specs to test the dismissal logic, leading to repetitive test code and maintenance overhead.
Current State
The GitLab codebase currently uses multiple approaches for dismissible alerts:
-
JavaScript-based alerts using
createAlert()fromapp/assets/javascripts/alert.js -
Server-side alerts using
Pajamas::AlertComponentwithdismissible: true - Custom dismissible components with their own dismissal logic
Each implementation requires individual feature specs to verify:
- Alert visibility
- Dismissal functionality
- Persistence of dismissal state
- Proper data attributes and endpoints
Examples of current dismissible alert usage:
ee/app/views/shared/_pipl_compliance_alert.html.hamlapp/views/projects/_lfs_misconfiguration_banner.html.hamlee/app/views/dashboard/projects/_joining_a_project_alert.haml
Requested Changes
Create a standardized DismissibleAlertComponent that:
- Encapsulates common dismissal logic - Handles the standard dismissal pattern used across GitLab
- Provides consistent testing interface - Includes well-tested dismissal behavior that doesn't require feature specs for each usage
-
Maintains backward compatibility - Works alongside existing
Pajamas::AlertComponentusage - Supports standard dismissal patterns - Integrates with existing callout helpers and dismissal endpoints
Proposed Implementation
Click to expand
1. Create DismissibleAlertComponent
# app/components/dismissible_alert_component.rb
class DismissibleAlertComponent < Pajamas::AlertComponent
def initialize(
feature_id:,
dismiss_endpoint: nil,
user: nil,
**alert_options
)
@feature_id = feature_id
@dismiss_endpoint = dismiss_endpoint || default_dismiss_endpoint
@user = user || current_user
super(**alert_options.merge(
dismissible: true,
alert_options: build_alert_options(alert_options[:alert_options] || {})
))
end
private
def build_alert_options(existing_options)
existing_options.merge(
class: "js-dismissible-alert #{existing_options[:class]}",
data: {
feature_id: @feature_id,
dismiss_endpoint: @dismiss_endpoint,
**existing_options.fetch(:data, {})
}
)
end
def default_dismiss_endpoint
# Use Rails route helpers to generate appropriate endpoint
# This would need to be context-aware (project vs group vs user callouts)
end
end
2. Create comprehensive component specs
# spec/components/dismissible_alert_component_spec.rb
RSpec.describe DismissibleAlertComponent do
# Test dismissal logic, data attributes, endpoint configuration
# This comprehensive test suite eliminates need for feature specs
end
3. Create shared examples for integration testing
# spec/support/shared_examples/dismissible_alert_examples.rb
RSpec.shared_examples 'a dismissible alert' do |feature_id|
it 'renders with correct dismissal attributes' do
expect(page).to have_css("[data-feature-id='#{feature_id}']")
expect(page).to have_css('.js-dismissible-alert')
end
it 'can be dismissed', :js do
find('.js-close').click
expect(page).not_to have_css("[data-feature-id='#{feature_id}']")
end
end
4. Update existing dismissible alerts
Gradually migrate existing dismissible alerts to use the new component:
-# Before
= render Pajamas::AlertComponent.new(
dismissible: true,
alert_options: {
class: 'js-pipl-compliance-alert',
data: {
feature_id: Users::CalloutsHelper::PIPL_COMPLIANCE_ALERT,
dismiss_endpoint: callouts_path
}
}
)
-# After
= render DismissibleAlertComponent.new(
feature_id: Users::CalloutsHelper::PIPL_COMPLIANCE_ALERT,
dismiss_endpoint: callouts_path
)
Acceptance Criteria
-
DismissibleAlertComponentis created and inherits fromPajamas::AlertComponent -
Component automatically handles standard dismissal data attributes and CSS classes -
Component integrates with existing callout helpers ( Users::CalloutsHelper, etc.) -
Comprehensive component specs cover all dismissal scenarios -
Shared examples are available for integration testing -
Documentation is updated with usage examples -
At least 3 existing dismissible alerts are migrated to use the new component -
Feature specs for migrated alerts are simplified or removed -
Component supports both user-level and project-level dismissals
Technical Context
Affected Files:
-
app/components/dismissible_alert_component.rb(new) -
app/components/pajamas/alert_component.rb(reference) -
app/assets/javascripts/alert.js(integration) -
spec/components/dismissible_alert_component_spec.rb(new) -
spec/support/shared_examples/dismissible_alert_examples.rb(new)
Integration Points:
-
Users::CalloutsHelperfor user dismissals -
Projects::CalloutsHelperfor project-level dismissals - Existing dismissal endpoints (
callouts_path,project_callouts_path) - JavaScript dismissal handlers
Dependencies:
- Pajamas Design System components
- Existing callout infrastructure
- Rails view component framework
Priority: Medium - This is a developer experience improvement that will reduce maintenance overhead for future dismissible alerts.