easy-admin-rails 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a63d1ab4e8fc041e2a81a5016143d2ecc8bcd59794daa37e48b508c4909bc96d
4
- data.tar.gz: d93300f1d09125d7628a09c41ff248300b562c007494fe7c0fa1e4e50ef53316
3
+ metadata.gz: 714d6b87819aca514f1b6547871b544c36f7ba2d9941b3c235df73c6276fad3e
4
+ data.tar.gz: 42b81c8f6157e0589d4c39ea6684c836154b1e4d5a0c6ab22c723ad34604ab1d
5
5
  SHA512:
6
- metadata.gz: 3a792a8832756b6c22f372e471759de150bcf7eebc4e0dce477e4f0f762f690197542a1d69a2e444b3dce0dd17b2834b6610cea6bf4481485f16ca0918e9dff4
7
- data.tar.gz: fd6c58fbc7069b8a13f28e4ab8ef07c6788fdf4684529cf5aa05fef659b746287e54470702fb2726440505930c92562442c4ce0a6d44b1e035efe5d5b1a49d31
6
+ metadata.gz: b347e40183ea5cdfed508bf9921826defddb39f9dcd5701746b3622b44d4917a900df3cf029eb5c2decc5a792a313617127909588377f23cbdd6e977edee8d9e
7
+ data.tar.gz: feb58175155da2dcb224766ba9be58d3bc2837a7fbee6b64353ef823b3879bd164f95772d05f7695e80ee996b19bb84781c5faf0df770d1626c2d7c4da9adfc4
@@ -171,7 +171,7 @@ module EasyAdmin
171
171
 
172
172
  def render_filter_field(field)
173
173
  component_class = filter_component_for_field(field)
174
- render component_class.new(field: field, search_params: @search_params)
174
+ render component_class.new(field: field, search_params: @search_params, resource_class: @resource_class)
175
175
  end
176
176
 
177
177
  def filter_component_for_field(field)
@@ -54,8 +54,17 @@ module EasyAdmin
54
54
  url
55
55
  end
56
56
 
57
- # Override to always return empty options since we use suggest mode
57
+ # Override to return empty options for suggest mode unless custom options are provided
58
58
  def options
59
+ # Check if field has custom options (static or proc)
60
+ if field[:options]
61
+ opts = field[:options]
62
+ # If options is a Proc, evaluate it with the form object
63
+ opts = opts.call(form.object) if opts.is_a?(Proc)
64
+ return opts
65
+ end
66
+
67
+ # For suggest mode, return empty array
59
68
  []
60
69
  end
61
70
 
@@ -284,6 +284,15 @@ module EasyAdmin
284
284
  end
285
285
 
286
286
  def build_options
287
+ # Check if field has custom options (static or proc)
288
+ if field[:options]
289
+ opts = field[:options]
290
+ # If options is a Proc, evaluate it with the form object
291
+ opts = opts.call(form.object) if opts.is_a?(Proc)
292
+ return opts
293
+ end
294
+
295
+ # Otherwise build from available records
287
296
  available_options.map do |item|
288
297
  [display_text_for(item), item.id]
289
298
  end
@@ -46,7 +46,13 @@ module EasyAdmin
46
46
  end
47
47
 
48
48
  def options
49
- field[:options] || []
49
+ opts = field[:options] || []
50
+ # If options is a Proc, evaluate it with the form object
51
+ if opts.is_a?(Proc)
52
+ opts.call(form.object)
53
+ else
54
+ opts
55
+ end
50
56
  end
51
57
 
52
58
  def placeholder
@@ -3,9 +3,10 @@ module EasyAdmin
3
3
  module Index
4
4
  module Filters
5
5
  class BaseComponent < Phlex::HTML
6
- def initialize(field:, search_params: {})
6
+ def initialize(field:, search_params: {}, resource_class: nil)
7
7
  @field = field
8
8
  @search_params = search_params
9
+ @resource_class = resource_class
9
10
  end
10
11
 
11
12
  def view_template
@@ -4,6 +4,14 @@ module EasyAdmin
4
4
  module Filters
5
5
  class SelectComponent < BaseComponent
6
6
  private
7
+
8
+ def filter_field_name
9
+ @filter_field_name ||= if @field[:type] == :belongs_to
10
+ "#{@field[:name]}_id"
11
+ else
12
+ @field[:name]
13
+ end
14
+ end
7
15
 
8
16
  def render_filter_input
9
17
  div(
@@ -12,22 +20,39 @@ module EasyAdmin
12
20
  controller: "select-field",
13
21
  select_field_multiple_value: "false",
14
22
  select_field_placeholder_value: "Select #{@field[:label].downcase}...",
23
+ select_field_suggest_value: @field[:suggest].to_s,
24
+ select_field_suggest_url_value: @field[:suggest] ? suggest_url : "",
15
25
  field_name: @field[:name]
16
26
  }
17
27
  ) do
18
- # Display input
28
+ # Display/Search input
19
29
  div(class: "relative") do
20
- input(
21
- type: "text",
22
- class: single_select_input_classes,
23
- placeholder: "Select #{@field[:label].downcase}...",
24
- readonly: true,
25
- value: current_display_value,
26
- data: {
27
- select_field_target: "display",
28
- action: "click->select-field#toggleDropdown"
29
- }
30
- )
30
+ if @field[:suggest]
31
+ # For suggest mode, use a search input
32
+ input(
33
+ type: "text",
34
+ class: single_select_input_classes,
35
+ placeholder: "Type to search...",
36
+ value: current_display_value,
37
+ data: {
38
+ select_field_target: "search",
39
+ action: "input->select-field#filter keydown->select-field#handleKeydown focus->select-field#openDropdown"
40
+ }
41
+ )
42
+ else
43
+ # For static mode, use display input
44
+ input(
45
+ type: "text",
46
+ class: single_select_input_classes,
47
+ placeholder: "Select #{@field[:label].downcase}...",
48
+ readonly: true,
49
+ value: current_display_value,
50
+ data: {
51
+ select_field_target: "display",
52
+ action: "click->select-field#toggleDropdown"
53
+ }
54
+ )
55
+ end
31
56
  # Dropdown arrow
32
57
  div(class: "absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none") do
33
58
  unsafe_raw('<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>')
@@ -39,27 +64,35 @@ module EasyAdmin
39
64
  class: "select-dropdown absolute z-50 w-full mt-1 bg-white border border-gray-300 rounded-md shadow-lg max-h-60 overflow-auto opacity-0 invisible transform scale-95 transition-all duration-200 ease-out",
40
65
  data: { select_field_target: "dropdown" }
41
66
  ) do
42
- render_option("", "All")
43
-
44
- if @field[:options]
45
- @field[:options].each do |option_value, option_label|
46
- render_option(option_value, option_label)
67
+ if @field[:suggest]
68
+ # For suggest mode, options will be loaded dynamically
69
+ render_no_results_message
70
+ render_loading_message
71
+ else
72
+ # For static mode, render all options
73
+ render_option("", "All")
74
+
75
+ if @field[:options]
76
+ @field[:options].each do |option_value, option_label|
77
+ render_option(option_value, option_label)
78
+ end
47
79
  end
80
+ render_no_results_message
48
81
  end
49
82
  end
50
83
 
51
84
  # Hidden input for the actual value
52
85
  input(
53
86
  type: "hidden",
54
- name: "q[#{@field[:name]}_eq]",
55
- value: @search_params["#{@field[:name]}_eq"] || "",
87
+ name: "q[#{filter_field_name}_eq]",
88
+ value: @search_params["#{filter_field_name}_eq"] || "",
56
89
  data: { select_field_target: "hiddenInput" }
57
90
  )
58
91
  end
59
92
  end
60
93
 
61
94
  def render_option(value, text)
62
- selected = @search_params["#{@field[:name]}_eq"].to_s == value.to_s
95
+ selected = @search_params["#{filter_field_name}_eq"].to_s == value.to_s
63
96
 
64
97
  div(
65
98
  class: "select-option px-3 py-2 text-sm cursor-pointer hover:bg-blue-50 hover:text-blue-900 transition-colors duration-150 #{selected ? 'bg-blue-50 text-blue-900' : 'text-gray-900'}",
@@ -74,15 +107,48 @@ module EasyAdmin
74
107
  end
75
108
 
76
109
  def current_display_value
77
- return "All" if @search_params["#{@field[:name]}_eq"].blank?
110
+ return "All" if @search_params["#{filter_field_name}_eq"].blank?
78
111
 
79
112
  if @field[:options]
80
113
  @field[:options].each do |option_value, option_label|
81
- return option_label.to_s if option_value.to_s == @search_params["#{@field[:name]}_eq"].to_s
114
+ return option_label.to_s if option_value.to_s == @search_params["#{filter_field_name}_eq"].to_s
82
115
  end
83
116
  end
84
117
 
85
- @search_params["#{@field[:name]}_eq"].to_s
118
+ @search_params["#{filter_field_name}_eq"].to_s
119
+ end
120
+
121
+ def render_no_results_message
122
+ div(
123
+ class: "select-no-results px-3 py-2 text-sm text-gray-500 text-center",
124
+ data: { select_field_target: "noResults" },
125
+ style: "display: none;"
126
+ ) do
127
+ plain "No options found"
128
+ end
129
+ end
130
+
131
+ def render_loading_message
132
+ div(
133
+ class: "select-loading px-3 py-2 text-sm text-gray-500 text-center",
134
+ data: { select_field_target: "loading" },
135
+ style: "display: none;"
136
+ ) do
137
+ plain "Loading..."
138
+ end
139
+ end
140
+
141
+ def suggest_url
142
+ return "" unless @field[:suggest]
143
+
144
+ # Use the current resource being filtered (e.g., posts when filtering posts by user)
145
+ resource_name = @resource_class.route_key
146
+
147
+ easy_admin_url_helpers.suggest_resource_path(resource_name, field: @field[:name])
148
+ end
149
+
150
+ def easy_admin_url_helpers
151
+ EasyAdmin::Engine.routes.url_helpers
86
152
  end
87
153
 
88
154
  def single_select_input_classes
@@ -76,7 +76,7 @@ module EasyAdmin
76
76
 
77
77
  def render_filter_field(field)
78
78
  component_class = filter_component_for_field(field)
79
- render component_class.new(field: field, search_params: @search_params)
79
+ render component_class.new(field: field, search_params: @search_params, resource_class: @resource_class)
80
80
  end
81
81
 
82
82
  def filter_component_for_field(field)
@@ -49,19 +49,6 @@ module EasyAdmin
49
49
  SVG
50
50
  h3(class: "mt-2 text-sm font-semibold text-gray-900") { "No #{@resource_class.title.downcase}" }
51
51
  p(class: "mt-1 text-sm text-gray-500") { "Get started by creating a new #{@resource_class.singular_title.downcase}." }
52
- div(class: "mt-6") do
53
- a(
54
- href: easy_admin_url_helpers.new_resource_path(@resource_class.route_key),
55
- class: "inline-flex items-center rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
56
- ) do
57
- unsafe_raw <<~SVG
58
- <svg class="-ml-0.5 mr-1.5 h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
59
- <path d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z"/>
60
- </svg>
61
- SVG
62
- "New #{@resource_class.singular_title}"
63
- end
64
- end
65
52
  end
66
53
  end
67
54
 
@@ -85,4 +72,4 @@ module EasyAdmin
85
72
  end
86
73
  end
87
74
  end
88
- end
75
+ end
@@ -1,7 +1,7 @@
1
1
  import { Controller } from "@hotwired/stimulus"
2
2
 
3
3
  export default class extends Controller {
4
- static targets = ["search", "dropdown", "selectedItems", "option", "hiddenInput", "display", "noResults", "loading"]
4
+ static targets = ["search", "dropdown", "selectedItems", "option", "hiddenInput", "display", "noResults", "loading", "searchInput", "optionsContainer"]
5
5
  static values = { multiple: Boolean, placeholder: String, suggest: Boolean, suggestUrl: String }
6
6
 
7
7
  connect() {
@@ -615,4 +615,40 @@ export default class extends Controller {
615
615
  this.loadingTarget.style.display = 'none'
616
616
  }
617
617
  }
618
+
619
+ // Filter options for index page filters
620
+ filterOptions(event) {
621
+ const searchTerm = event.target.value.toLowerCase()
622
+
623
+ if (this.hasOptionsContainerTarget) {
624
+ // For index page filters
625
+ const options = this.optionsContainerTarget.querySelectorAll('[data-select-field-target="option"]')
626
+ let visibleCount = 0
627
+
628
+ options.forEach(option => {
629
+ const text = option.textContent.toLowerCase()
630
+ if (text.includes(searchTerm)) {
631
+ option.style.display = 'block'
632
+ visibleCount++
633
+ } else {
634
+ option.style.display = 'none'
635
+ }
636
+ })
637
+
638
+ // Show/hide no results message
639
+ if (visibleCount === 0 && this.hasNoResultsTarget) {
640
+ this.noResultsTarget.style.display = 'block'
641
+ this.noResultsTarget.textContent = 'No results found'
642
+ } else if (this.hasNoResultsTarget) {
643
+ this.noResultsTarget.style.display = 'none'
644
+ }
645
+ } else {
646
+ // Fallback to existing filter logic
647
+ this.filter(event)
648
+ }
649
+ }
650
+
651
+ stopPropagation(event) {
652
+ event.stopPropagation()
653
+ }
618
654
  }
@@ -1,3 +1,3 @@
1
1
  module EasyAdmin
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.8"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy-admin-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Slaurmagan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-01 00:00:00.000000000 Z
11
+ date: 2025-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails