Module: Spree::Admin::NavigationHelper

Defined in:
app/helpers/spree/admin/navigation_helper.rb

Instance Method Summary collapse

Instance Method Details

#active_badge(condition, options = {}) ⇒ String

renders a badge (active/inactive)

Parameters:

  • condition (Boolean)

    the condition to check

  • options (Hash) (defaults to: {})

    the options for the badge

Returns:

  • (String)

    the badge with the icon



225
226
227
228
229
230
231
232
233
234
235
# File 'app/helpers/spree/admin/navigation_helper.rb', line 225

def active_badge(condition, options = {})
  label = options[:label]
  label ||= condition ? Spree.t(:say_yes).to_s : Spree.t(:say_no).to_s
  label = icon('check') + label if condition

  css_class = condition ? 'badge-active' : 'badge-inactive'

  (:span, class: "badge  #{css_class}") do
    label
  end
end

renders an active link with an icon, using the active_link_to method from github.com/comfy/active_link_to gem

Parameters:

  • icon_name (String)

    the name of the icon, eg: ‘pencil’, see: tabler.io/icons

  • text (String)

    the text of the link

  • url (String)

    the url of the link

  • options (Hash) (defaults to: {})

    the options for the link

Returns:

  • (String)

    the active link with the icon



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'app/helpers/spree/admin/navigation_helper.rb', line 149

def active_link_to_with_icon(icon_name, text, url, options = {})
  no_text = options[:no_text]
  tooltip_text = options[:title] || (no_text ? text : nil)
  options.delete(:no_text)
  options.delete(:title) if tooltip_text

  if tooltip_text
    options[:data] ||= {}
    options[:data][:controller] = 'tooltip'
  end

  label = no_text ? '' : (:span, text)

  if icon_name
    icon = icon(icon_name, class: "icon icon-#{icon_name}")
    text = "#{icon} #{label}"
  end

  link_content = text.html_safe
  link_content += tooltip(tooltip_text) if tooltip_text

  active_link_to(link_content, url, options)
end

#button(text, icon_name = nil, button_type = 'submit', options = {}) ⇒ String

renders a button with an icon (optional) Override: Add disable_with option to prevent multiple request on consecutive clicks

Parameters:

  • text (String)

    the text of the button

  • icon_name (String) (defaults to: nil)

    the name of the icon, eg: ‘pencil’, see: tabler.io/icons

  • button_type (String) (defaults to: 'submit')

    the type of the button, eg: ‘submit’, ‘button’

  • options (Hash) (defaults to: {})

    the options for the button

Returns:

  • (String)

    the button with the icon



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'app/helpers/spree/admin/navigation_helper.rb', line 180

def button(text, icon_name = nil, button_type = 'submit', options = {})
  if icon_name
    text = "#{icon(icon_name, class: "icon icon-#{icon_name}")} #{text}"
  end

  css_classes = options[:class] || 'btn-primary'

  button_tag(
    text.html_safe,
    options.merge(
      type: button_type,
      class: "btn #{css_classes}",
      'data-turbo-submits-with' => (:span, '', class: 'inline-block w-4 h-4 border-2 border-current border-r-transparent rounded-full animate-spin', role: 'status')
    )
  )
end


197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'app/helpers/spree/admin/navigation_helper.rb', line 197

def button_link_to(text, url, html_options = {})
  Spree::Deprecation.warn("button_link_to is deprecated. Use standard link_to instead.")

  if html_options[:method] &&
      !html_options[:method].to_s.casecmp('get').zero? &&
      !html_options[:remote]

    html_options[:class] = html_options[:class] ? "btn #{html_options[:class]}" : 'btn btn-primary'

    form_tag(url, method: html_options.delete(:method)) do
      button(text, html_options.delete(:icon), nil, html_options)
    end
  else
    html_options[:class] = html_options[:class] ? "btn #{html_options[:class]}" : 'btn btn-light'

    if html_options[:icon]
      icon = icon(html_options[:icon], class: "icon icon-#{html_options[:icon]}")
      text = "#{icon} #{text}"
    end

    link_to(text.html_safe, url, html_options.except(:icon))
  end
end

renders an external link with an icon (eg. spree documentation website)

Parameters:

  • label (String)

    the label of the link

  • url (String)

    the url of the link

  • opts (Hash) (defaults to: {})

    the options for the link

Returns:

  • (String)

    the external link with the icon



261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'app/helpers/spree/admin/navigation_helper.rb', line 261

def external_link_to(label, url, opts = {}, &block)
  opts[:target] ||= :blank
  opts[:rel] ||= :nofollow
  opts[:class] ||= "inline-flex items-center text-blue-500 no-underline hover:text-blue-600 hover:bg-blue-50 p-1 rounded"

  if block_given?
    link_to url, opts, &block
  else
    link_to url, opts do
      (label + icon('external-link', class: 'ml-1 mr-0 small opacity-50')).html_safe
    end
  end
end

renders a link to preview a resource on the storefront using the spree_storefront_resource_url helper

Parameters:

  • resource (Spree::Product)

    the resource to preview

  • options (Hash) (defaults to: {})

    the options for the link

Returns:

  • (String)

    the link to preview the resource



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'app/helpers/spree/admin/navigation_helper.rb', line 279

def external_page_preview_link(resource, options = {})
  resource_name = options[:name] || resource.class.name.demodulize

  url = if resource.instance_of?(Spree::Product)
          spree_storefront_resource_url(resource, preview_id: resource.id)
        else
          spree_storefront_resource_url(resource)
        end

  link_to_with_icon(
    'eye',
    Spree.t('admin.utilities.preview', name: resource_name),
    url,
    class: 'text-left dropdown-item', id: "adminPreview#{resource_name}", target: :blank, data: { turbo: false }
  )
end

#help_bubble(text = '', placement = 'top', css: nil) ⇒ String

renders a help bubble with an icon

Parameters:

  • text (String) (defaults to: '')

    the text of the help bubble

  • placement (String) (defaults to: 'top')

    the placement of the help bubble

  • css (String) (defaults to: nil)

    the css class of the help bubble

Returns:

  • (String)

    the help bubble with the icon



301
302
303
304
305
306
# File 'app/helpers/spree/admin/navigation_helper.rb', line 301

def help_bubble(text = '', placement = 'top', css: nil)
  css ||= 'text-gray-500 cursor-default opacity-75'
   :span, data: { controller: 'tooltip', tooltip_placement_value: placement } do
    icon('info-square-rounded', class: css) + tooltip(text)
  end
end

render a button to delete a resource with a confirmation modal if the current user doesn’t have permission to destroy the resource, the button will not be rendered

Parameters:

  • resource (Spree::Product, Spree::User, Spree::Order)

    the resource to delete

  • options (Hash) (defaults to: {})

    the options for the link

Options Hash (options):

  • :url (String)

    the url to delete the resource (optional)

Returns:

  • (String)

    the link to delete the resource



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'app/helpers/spree/admin/navigation_helper.rb', line 87

def link_to_delete(resource, options = {})
  url = options[:url] || object_url(resource)
  name = options[:name] || Spree.t('actions.destroy')
  options[:class] ||= 'btn btn-danger btn-sm'
  options[:data] ||= { turbo_confirm: Spree.t(:are_you_sure), turbo_method: :delete }

  return unless can?(:destroy, resource)

  if options[:no_text]
    link_to_with_icon 'trash', name, url, options
  elsif options[:icon]
    link_to_with_icon options[:icon], name, url, options
  else
    link_to name, url, options
  end
end

render a button link to edit a resource if the current user doesn’t have permission to update the resource, the button will not be rendered

Parameters:

  • resource (Spree::Product, Spree::User, Spree::Order)

    the resource to edit

  • options (Hash) (defaults to: {})

    the options for the link

Options Hash (options):

  • :url (String)

    the url to edit the resource (optional)

Returns:

  • (String)

    the link to edit the resource



73
74
75
76
77
78
79
# File 'app/helpers/spree/admin/navigation_helper.rb', line 73

def link_to_edit(resource, options = {})
  url = options[:url] || edit_object_url(resource)
  options[:data] ||= {}
  options[:data][:action] ||= 'edit'
  options[:class] ||= 'btn btn-light btn-sm'
  link_to_with_icon('pencil', Spree.t(:edit), url, options) if can?(:update, resource)
end


134
135
136
137
138
139
140
141
# File 'app/helpers/spree/admin/navigation_helper.rb', line 134

def link_to_export_modal
  return unless can?(:create, Spree::Export)

  button_tag(type: 'button', class: 'btn btn-light', data: { action: 'click->export-dialog#open' }) do
    icon('table-export', class: 'mr-0 mr-lg-2') +
    (:span, Spree.t(:export), class: 'hidden lg:inline')
  end
end

renders a link with an icon

Parameters:

  • icon_name (String)

    the name of the icon, eg: ‘pencil’, see: tabler.io/icons

  • text (String)

    the text of the link

  • url (String)

    the url of the link

  • options (Hash) (defaults to: {})

    the options for the link

Returns:

  • (String)

    the link with the icon



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'app/helpers/spree/admin/navigation_helper.rb', line 110

def link_to_with_icon(icon_name, text, url, options = {})
  no_text = options[:no_text]
  tooltip_text = options[:title] || (no_text ? text : nil)
  options.delete(:no_text)
  options.delete(:title) if tooltip_text

  if tooltip_text
    options[:data] ||= {}
    options[:data][:controller] = 'tooltip'
  end

  label = no_text ? '' : (:span, text)

  if icon_name
    icon = icon(icon_name, class: "icon icon-#{icon_name} #{text.blank? || no_text ? 'mr-0' : ''}")
    text = "#{icon} #{label}"
  end

  link_content = text.html_safe
  link_content += tooltip(tooltip_text) if tooltip_text

  link_to(link_content, url, options)
end

Creates a navigation item with optional icon

Parameters:

  • label (String, SafeBuffer) (defaults to: nil)

    The text or HTML to use as the link content

  • url (String)

    The URL for the link

  • icon (String, nil) (defaults to: nil)

    Optional icon name to prepend to the label

  • active (Boolean, nil) (defaults to: nil)

    Whether the link should be marked as active

Returns:

  • (SafeBuffer)

    The navigation item HTML



10
11
12
13
14
15
16
17
18
19
20
21
# File 'app/helpers/spree/admin/navigation_helper.rb', line 10

def nav_item(label = nil, url, icon: nil, active: nil, data: {}, **options)
   :li, class: 'nav-item', role: 'presentation' do
    if block_given?
      active_link_to url, class: 'nav-link', active: active, data: data, **options do
        yield
      end
    else
      label = icon(icon) + label if icon.present? && label.present?
      active_link_to label, url, class: 'nav-link', active: active, data: data, **options
    end
  end
end

Get navigation items for the given context

Parameters:

  • context (Symbol) (defaults to: :sidebar)

    the navigation context

Returns:



330
331
332
333
# File 'app/helpers/spree/admin/navigation_helper.rb', line 330

def navigation_items(context = :sidebar)
  # Pass the view context (self) so that can? and other helpers are available
  Spree.admin.navigation.send(context)&.visible_items(self) || []
end

#page_header_back_button(default_url, object = nil, label = nil) ⇒ String

renders a back button to the previous page

Parameters:

  • default_url (String)

    the default url to go back to

  • object (Spree::Product, Spree::User, Spree::Order) (defaults to: nil)

    the object list to go back to

  • label (String) (defaults to: nil)

    the label of the back button (optional)

Returns:

  • (String)

    the back button



242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'app/helpers/spree/admin/navigation_helper.rb', line 242

def page_header_back_button(default_url, object = nil, label = nil)
  url = default_url

  if object.present?
    session_key = "#{object.class.to_s.demodulize.pluralize.downcase}_return_to".to_sym
    url = session[session_key] if session[session_key].present?
  end

  link_to url, class: 'flex items-center no-underline' do
    (:span, icon('chevron-left', class: 'mr-0'), class: 'btn hover:bg-gray-100 shadow-none px-2 flex items-center shadow-none') +
      (:span, label, class: 'font-size-base text-black')
  end
end

#per_page_dropdownString

the per_page_dropdown is used on index pages like orders, products, promotions etc. this method generates the select_tag

Returns:

  • (String)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'app/helpers/spree/admin/navigation_helper.rb', line 26

def per_page_dropdown
  per_page_default = if @products
                       Spree::Admin::RuntimeConfig.admin_products_per_page
                     elsif @orders
                       Spree::Admin::RuntimeConfig.admin_orders_per_page
                     else
                       Spree::Admin::RuntimeConfig.admin_records_per_page
                     end

  per_page_options = [
    per_page_default,
    per_page_default * 2,
    per_page_default * 4,
    per_page_default * 8
  ]

  selected_option = (params[:per_page].try(:to_i) || per_page_default).to_i
  selected_option_label = selected_option.to_s + icon('chevron-down', class: 'ml-1 mr-0 arrow')

  dropdown(id: 'per-page-dropdown', portal: false) do
    dropdown_toggle(class: 'btn-light btn-sm') do
      raw(selected_option_label)
    end +
    dropdown_menu(direction: 'top-left') do
      per_page_options.map do |option|
        link_to option, per_page_dropdown_params(option), class: "dropdown-item #{'active' if option.to_i == selected_option}"
      end.join.html_safe
    end
  end
end

#per_page_dropdown_params(per_page) ⇒ Hash

helper method to create proper url to apply per page ing fixes github.com/spree/spree/issues/6888

Parameters:

  • per_page (Integer)

    the number of items per page

Returns:

  • (Hash)

    the params to apply per page



61
62
63
64
65
# File 'app/helpers/spree/admin/navigation_helper.rb', line 61

def per_page_dropdown_params(per_page)
  # Keep only safe query params that should survive pagination changes
  safe_params = request.query_parameters.slice(:q)
  safe_params.merge(per_page: per_page, page: nil)
end

#render_breadcrumb_iconObject



308
309
310
311
312
313
314
# File 'app/helpers/spree/admin/navigation_helper.rb', line 308

def render_breadcrumb_icon
  if settings_area?
    icon('settings')
  elsif @breadcrumb_icon
    icon(@breadcrumb_icon)
  end
end

#render_navigation(context = :sidebar, **options) ⇒ String

Renders the navigation for the given context

Parameters:

  • context (Symbol) (defaults to: :sidebar)

    the navigation context (:sidebar, :settings, etc.)

  • options (Hash)

    additional options for rendering

Returns:

  • (String)

    the rendered navigation HTML



320
321
322
323
324
325
# File 'app/helpers/spree/admin/navigation_helper.rb', line 320

def render_navigation(context = :sidebar, **options)
  items = navigation_items(context)
  return '' if items.empty?

  render_navigation_items(items, context)
end

#render_navigation_item(item, context) ⇒ SafeBuffer

Renders a single navigation item

Parameters:

Returns:

  • (SafeBuffer)

    the rendered HTML



351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'app/helpers/spree/admin/navigation_helper.rb', line 351

def render_navigation_item(item, context)
  return render_nav_section_header(item) if item.section?

  item_url = item.resolve_url(self)
  item_label = item.resolve_label
  badge_value = item.badge_value(self)
  is_active = item.active?(request.path, self)
  has_children = item.children.present?
  tooltip_text = item.tooltip

  # Build data attributes
  data_attrs = item.data_attributes.dup
  data_attrs[:controller] = 'tooltip' if tooltip_text.present?

  # Build HTML options
  html_options = {}
  html_options[:target] = item.target if item.target.present?
  html_options[:id] = "nav-link-#{item.key}" if item.key.present?

  # Build complete label with badge and tooltip
  complete_label = build_nav_label(item_label, badge_value, item.badge_class, tooltip_text)

  if has_children
    render_nav_item_with_children(item, complete_label, item_url, item_label, is_active, data_attrs, html_options, context)
  else
    nav_item(complete_label, item_url, icon: item.icon, active: is_active, data: data_attrs, **html_options)
  end
end

#render_navigation_items(items, context) ⇒ SafeBuffer

Renders navigation items as an unordered list

Parameters:

Returns:

  • (SafeBuffer)

    the rendered HTML



339
340
341
342
343
344
345
# File 'app/helpers/spree/admin/navigation_helper.rb', line 339

def render_navigation_items(items, context)
  return ''.html_safe if items.empty?

   :ul, class: 'nav flex-col' do
    safe_join(items.map { |item| render_navigation_item(item, context) })
  end
end

#render_tab_navigation(context, **options) ⇒ String

Renders page tab navigation for the given context

Parameters:

  • context (Symbol)

    the navigation context (:tax_tabs, :shipping_tabs, etc.)

  • options (Hash)

    additional options for rendering

Returns:

  • (String)

    the rendered tab navigation HTML wrapped in content_for(:page_tabs)



384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'app/helpers/spree/admin/navigation_helper.rb', line 384

def render_tab_navigation(context, **options)
  items = navigation_items(context)
  return '' if items.empty?

  content_for :page_tabs do
    items.map do |item|
      item_url = item.resolve_url(self)
      item_label = item.resolve_label
      is_active = item.active?(request.path, self)

      nav_item(item_label, item_url, active: is_active)
    end.join.html_safe
  end
end