Module: Crm::ImagesHelper

Defined in:
app/helpers/crm/images_helper.rb

Overview

View helper: images.

Renders action-link groups and metadata snippets for CRM image pages.

See Also:

  • ImagesController

Instance Method Summary collapse

Instance Method Details

#image_command_options(image = @image) ⇒ Array<String>

Builds the command links (edit, transform, clone, purge, upscale, etc.) for an image page.

Parameters:

  • image (Image) (defaults to: @image)

    the image the commands act on; defaults to the controller-provided @image

Returns:

  • (Array<String>)

    HTML link strings to render in the command panel



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'app/helpers/crm/images_helper.rb', line 12

def image_command_options(image = @image)
  [].tap do |links|
    links << link_to(fa_icon('wrench', text: 'Edit Image'), edit_image_path(image.id)) if can?(:update, image)
    links << link_to(fa_icon('wrench', text: 'Edit Image Profiles'), edit_image_profiles_image_path(@image)) if can?(:update, image)
    links << link_to(fa_icon('crop', text: 'Transform'), transform_image_path(image))
    links << link_to(fa_icon('clone', text: 'Clone Image'), clone_image_path(image.id)) if can?(:create, Image)
    links << link_to(fa_icon('broom', text: 'Purge Cache'), purge_cache_image_path(image), data: { turbo_method: :post })
    links << link_to(fa_icon('image', text: 'Make Primary Image of Items'), make_primary_item_image_image_path(image), data: { turbo_method: :post })
    # AI Upscale - always available for users who can update images
    links << link_to(fa_icon('expand', text: 'Upscale Image'), upscale_preview_image_path(image)) if can?(:update, image)
    # AI Generation - generate a variation of this image
    links << link_to(fa_icon('wand-magic-sparkles', text: 'Generate Variation'), new_generated_image_path(source_image_id: image.id)) if can?(:update, image) && ImageGeneration::Service.available?
    # Find Similar - only show if image has visual embedding
    links << link_to(fa_icon('images', text: 'Find Similar Images'), find_similar_image_path(image)) if image_has_visual_embedding?(image)
    links << link_to(fa_icon('trash', text: 'Delete'), image_path(image), data: { turbo_method: :delete, turbo_confirm: 'Are you sure?' }) if can?(:destroy, image)
  end
end

#image_download_options(image = @image) ⇒ Array<String>

Builds the download/copy links for an image: a "Copy URL" clipboard link
plus one download link per supported output format.

Parameters:

  • image (Image) (defaults to: @image)

    the image to download; defaults to the controller-provided @image

Returns:

  • (Array<String>)

    HTML link strings to render in the download panel



44
45
46
47
48
49
50
51
52
53
# File 'app/helpers/crm/images_helper.rb', line 44

def image_download_options(image = @image)
  copy_link = tag.a(fa_icon('copy', text: 'Copy URL'),
                    href: '#',
                    data: { controller: 'clipboard',
                            clipboard_text_value: image.image_url,
                            action: 'click->clipboard#copy' })
  encode_formats = [image.attachment_format&.to_sym, :png, :jpeg, :webp, :avif, :tiff].compact.uniq
  download_links = encode_formats.map { |encode_format| link_to(fa_icon('download', text: "Download #{encode_format.to_s.upcase}"), image.image_url(encode_format:, download: true)) }
  [copy_link] + download_links
end

#image_has_visual_embedding?(image) ⇒ Boolean

Checks if image has a unified embedding for visual similarity search.

Parameters:

  • image (Image)

    the image to check

Returns:

  • (Boolean)

    true when a unified visual embedding is present



34
35
36
37
# File 'app/helpers/crm/images_helper.rb', line 34

def image_has_visual_embedding?(image)
  unified = image.find_content_embedding(:unified)
  unified&.unified_embedding.present?
end

#image_info(image) ⇒ String

Builds a plain-text summary of an image's key attributes (title, slug,
dimensions, position, tags, locales).

Parameters:

  • image (Image)

    the image to describe

Returns:

  • (String)

    newline-separated attribute lines



69
70
71
72
73
74
75
76
77
78
79
# File 'app/helpers/crm/images_helper.rb', line 69

def image_info(image)
  [
    "Title: #{image.title}",
    "Slug: #{image.slug}",
    "Dimensions: #{image.dimensions}",

    "Position: #{image.position}",
    "Tags: #{image.tags.join(', ')}",
    "Locales: #{image.locales&.join(', ')}"
  ].join("\n")
end

#item_image_command_options(item:, image:, return_path: nil) ⇒ Array<String>

Builds the command links for an image shown in the context of an item's
images tab (view/edit the image, change the item's primary image, assign
the image to slots).

Parameters:

  • item (Item, nil)

    the item whose images tab is being rendered

  • image (Image)

    the image the commands act on

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

    URL to return to after viewing/editing;
    defaults to the item's images tab

Returns:

  • (Array<String>)

    HTML link strings to render in the command panel



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'app/helpers/crm/images_helper.rb', line 90

def item_image_command_options(item:, image:, return_path: nil)
  return_path ||= item_path(item.id, tab: 'images')
  [].tap do |links|
    links << link_to('View Image', image_path(image, return_path: return_path), data: { turbo_frame: '_top' })
    links << link_to('Edit Image', edit_image_path(image, return_path: return_path), target: :_blank, rel: :noopener)

    if item && can?(:manage, item)
      images_return_path = item_path(item.id, tab: 'images', tag: @selected_tag, image_locale: @image_locale)
      links << if item.primary_image_id == image.id
                 link_to('Change Item Primary Image', edit_item_path(item, section: 'images', return_path: images_return_path))
               else
                 link_to('Make Primary Image of Item', make_primary_image_item_path(item, image_id: image.id, return_path: images_return_path), data: { turbo_method: :post })
               end

      # Count how many slots this image already covers (summary badge in the label)
      assigned_count = @image_profile_types_by_image_id&.dig(image.id)&.size || 0
      label = assigned_count > 0 ? "Assign to Slots... (#{assigned_count} ✓)" : 'Assign to Slots...'
      dialog_url = slot_assignment_dialog_image_profile_manager_path(item, image_id: image.id, content_locale: 'en')

      links << link_to(label, '#',
                       data: {
                         controller: 'dialog-trigger',
                         action: 'click->dialog-trigger#open',
                         dialog_trigger_dialog_value: 'imageProfileDialog',
                         dialog_trigger_src_value: dialog_url
                       })
    end
  end
end

#panel_title_with_badge(title, count) ⇒ String

Renders a panel title with a count badge appended.

Parameters:

  • title (String)

    the panel title text

  • count (Integer)

    the number shown inside the badge

Returns:

  • (String)

    HTML string with the badge markup



60
61
62
# File 'app/helpers/crm/images_helper.rb', line 60

def panel_title_with_badge(title, count)
  "#{title} <span class='badge bg-secondary ms-1'>#{count}</span>"
end