diff --git a/app/assets/javascripts/vue_shared/components/crud_component.vue b/app/assets/javascripts/vue_shared/components/crud_component.vue
index 00e9015e87f70fc1f8812996f0fe6b9a2c6ed312..5c7d899eb64773306405f8e932a0f36d95db0fcd 100644
--- a/app/assets/javascripts/vue_shared/components/crud_component.vue
+++ b/app/assets/javascripts/vue_shared/components/crud_component.vue
@@ -53,6 +53,11 @@ export default {
required: false,
default: false,
},
+ containerTag: {
+ type: String,
+ required: false,
+ default: 'section',
+ },
isLoading: {
type: Boolean,
required: false,
@@ -164,7 +169,8 @@ export default {
-
+
diff --git a/app/components/layouts/crud_component.haml b/app/components/layouts/crud_component.haml
index d7ac74ac8c826e56fb46635039e75b5574092dff..71321e90ea5282666a93c3a98d254c508776ccb0 100644
--- a/app/components/layouts/crud_component.haml
+++ b/app/components/layouts/crud_component.haml
@@ -1,4 +1,4 @@
-%section.crud.gl-bg-subtle.gl-border.gl-border-section.gl-rounded-base{ options_attrs, id: id }
+= content_tag @container_tag, **options_attrs, id: id do
%header.crud-header.gl-flex.gl-flex-wrap.gl-justify-between.gl-gap-x-5.gl-gap-y-2.gl-px-5.gl-py-4.gl-bg-section.gl-border-b.gl-border-section.gl-rounded-t-base.gl-relative{ class: ('gl-pr-10' if @is_collapsible) }
.gl-flex.gl-flex-col.gl-self-center
%h2.gl-text-base.gl-font-bold.gl-leading-normal.gl-inline-flex.gl-gap-3.gl-m-0{ data: { testid: 'crud-title' } }
diff --git a/app/components/layouts/crud_component.rb b/app/components/layouts/crud_component.rb
index 3a847cedd757837cef1ee4f3c4ad7383b91253ed..99576d7e0dbc9ef4818cbaf242706d6a3aaa7ca9 100644
--- a/app/components/layouts/crud_component.rb
+++ b/app/components/layouts/crud_component.rb
@@ -15,11 +15,12 @@ class CrudComponent < ViewComponent::Base
# @param [Hash] toggle_options
# @param [Hash] footer_options
# @param [Boolean] is_collapsible
+ # @param [String] container_tag
def initialize(
title, description: nil, count: nil, icon: nil, icon_class: nil,
toggle_text: nil, options: {}, count_options: {}, body_options: {},
form_options: {}, toggle_options: {}, footer_options: {},
- is_collapsible: false
+ is_collapsible: false, container_tag: 'section'
)
@title = title
@description = description
@@ -34,6 +35,7 @@ def initialize(
@toggle_options = toggle_options
@footer_options = footer_options
@is_collapsible = is_collapsible
+ @container_tag = container_tag
end
renders_one :description
@@ -48,11 +50,13 @@ def id
end
def options_attrs
+ default_testid = 'haml-crud'
default_classes = [
+ 'crud', 'gl-bg-subtle', 'gl-border', 'gl-border-section', 'gl-rounded-base',
('js-toggle-container' if @toggle_text),
('js-crud-collapsible-section' if @is_collapsible)
]
- @options.merge(default_attrs(@options, nil, default_classes))
+ @options.merge(default_attrs(@options, default_testid, default_classes))
end
def body_options_attrs
diff --git a/spec/components/layouts/crud_component_spec.rb b/spec/components/layouts/crud_component_spec.rb
index 5c4cc1ff49d3ebefa6dfcc00d4ee41fd3e41e03a..577e78637b3d73a9f335b6efa1ed72817f164c3a 100644
--- a/spec/components/layouts/crud_component_spec.rb
+++ b/spec/components/layouts/crud_component_spec.rb
@@ -15,6 +15,13 @@
let(:pagination) { 'Pagination' }
let(:component_title) { described_class.new(title) }
+ describe 'container_tag' do
+ it 'renders the element specified by container_tag option' do
+ render_inline described_class.new(title, container_tag: :div)
+ expect(page).to have_selector('div[data-testid="haml-crud"]')
+ end
+ end
+
describe 'slots' do
it 'renders title' do
render_inline component_title
diff --git a/spec/frontend/vue_shared/components/crud_component_spec.js b/spec/frontend/vue_shared/components/crud_component_spec.js
index 01bc9914852aab9b634a739a0e4fabef2f463230..f88820663064e3d69c9ba7713ac1e4accdf063b3 100644
--- a/spec/frontend/vue_shared/components/crud_component_spec.js
+++ b/spec/frontend/vue_shared/components/crud_component_spec.js
@@ -46,6 +46,11 @@ describe('CRUD Component', () => {
expect(findTitle().text()).toBe('CRUD Component title');
});
+ it('renders the element specified by the containerTag prop', () => {
+ createComponent({ containerTag: 'span' });
+ expect(wrapper.element.tagName).toBe('SPAN');
+ });
+
it('renders `title` slot', () => {
createComponent({}, { title: '
Title slot
' });