power_grid 0.1.1 → 0.2.0

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: 49ae8e5529e18a9de9cdcbec5d87e1f5343e5dfe4e455ce440161c9f7647916c
4
- data.tar.gz: 235bd1d01c227fc5fb06d0aa49c8babb48be5b71e387c2cdd89eed245cc845a5
3
+ metadata.gz: 41ecea06e53d056880150b46b4df3bce98af40631d2e4c8092b0389c97662cad
4
+ data.tar.gz: 816ce274026b3cf42f4e5d200ff16f874920db45cf8130dba2b0ac0aa31d4249
5
5
  SHA512:
6
- metadata.gz: 6fc5072d3feb68a862bc21eba89a9cf8e850f35fb4f88fdaf4bb2d08148e344157daab5dc78f6355d8f0b733807648a8e58673bb412e3d5bbc7ba952d8aba145
7
- data.tar.gz: 76e2486fa433cdd5634d67cadc53596ff5781a0498513a41f805880c0456190d055d2769d18375fa84f845a2ea75a16ba275862e32e8706e1451afeb2893fa64
6
+ metadata.gz: ec2f602a81ae2e5d2ecb77cb476a75421dc4d20607870193b019c6bd14cef66f65d4adbae76dd3235b6b1f248544cfffcd045520d841ef7db707cf7f2ecaf70d
7
+ data.tar.gz: acbe88c38a671072bbd2b88f85cb812251872a2d4b05fd11af746ec292447b9a1877e3c3022e2c921fc715421bd4ea1a110be00a12913db1195091735799a83d
@@ -1,40 +1,68 @@
1
1
  <div class="power-grid-container w-full bg-white dark:bg-slate-900 rounded-lg shadow ring-1 ring-slate-900/5" data-controller="power-grid-table">
2
2
 
3
- <!-- Top Controls: Per Page & Search -->
4
- <div class="flex flex-col sm:flex-row justify-between items-center p-4 border-b border-slate-200 dark:border-slate-700 space-y-3 sm:space-y-0">
5
- <!-- Per Page -->
6
- <div class="flex items-center text-sm text-slate-700 dark:text-slate-300">
7
- <span class="mr-2">Show</span>
8
- <%= form_with url: request.path, method: :get, data: { turbo_frame: "power_grid_table", turbo_action: "advance", power_grid_table_target: "form" }, class: "inline-block", id: "power_grid_form_#{request.path.parameterize}" do |f| %>
9
- <% params.except(:per_page, :page).each do |key, value| %>
10
- <%= hidden_field_tag key, value %>
3
+ <!-- Top Controls: Per Page & Search & Filters -->
4
+ <div class="flex flex-col space-y-4 p-4 border-b border-slate-200 dark:border-slate-700">
5
+ <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center space-y-3 sm:space-y-0 text-sm">
6
+
7
+ <!-- Left: Per Page & Filters -->
8
+ <div class="flex flex-wrap items-center gap-4 w-full sm:w-auto">
9
+ <%= form_with url: request.path, method: :get, data: { turbo_frame: "power_grid_table", turbo_action: "advance", power_grid_table_target: "form" }, class: "flex flex-wrap items-center gap-4 w-full", id: "power_grid_form_#{request.path.parameterize}" do |f| %>
10
+ <% params.except(:per_page, :page, :q, *(@grid.class.defined_filters.keys)).each do |key, value| %>
11
+ <%= hidden_field_tag key, value %>
12
+ <% end %>
13
+ <!-- Reset page to 1 on update -->
14
+ <%= hidden_field_tag :page, 1 %>
15
+
16
+ <!-- Per Page -->
17
+ <div class="flex items-center">
18
+ <span class="mr-2 text-slate-700 dark:text-slate-300">Show</span>
19
+ <%= select_tag :per_page, options_for_select([10, 25, 50, 100], @grid.per_page),
20
+ class: "block w-20 rounded-md border-slate-300 py-1.5 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm dark:bg-slate-800 dark:border-slate-600 dark:text-white",
21
+ data: { action: "change->power-grid-table#search" }
22
+ %>
23
+ </div>
24
+
25
+ <!-- Dynamic Filters -->
26
+ <% @grid.class.defined_filters.each do |name, options| %>
27
+ <div class="flex items-center">
28
+ <% if options[:collection] %>
29
+ <%= select_tag name, options_for_select(options[:collection], params[name]),
30
+ include_blank: options[:label] || name.to_s.humanize,
31
+ class: "block w-40 rounded-md border-slate-300 py-1.5 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm dark:bg-slate-800 dark:border-slate-600 dark:text-white",
32
+ data: { action: "change->power-grid-table#search" }
33
+ %>
34
+ <% else %>
35
+ <%= text_field_tag name, params[name],
36
+ placeholder: options[:label] || name.to_s.humanize,
37
+ class: "block w-40 rounded-md border-slate-300 py-1.5 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm dark:bg-slate-800 dark:border-slate-600 dark:text-white",
38
+ data: { action: "change->power-grid-table#search" } # Debounce handled by controller if implemented for change, otherwise change triggers immediately
39
+ %>
40
+ <% end %>
41
+ </div>
42
+ <% end %>
43
+
11
44
  <% end %>
12
- <!-- Reset page to 1 on limit change -->
13
- <%= hidden_field_tag :page, 1 %>
14
-
15
- <%= select_tag :per_page, options_for_select([10, 25, 50, 100], @grid.per_page),
16
- class: "mx-1 mt-1 block w-20 rounded-md border-slate-300 py-1.5 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm dark:bg-slate-800 dark:border-slate-600 dark:text-white",
17
- data: { action: "change->power-grid-table#search" }
18
- %>
19
- <% end %>
20
- <span class="ml-2">entries</span>
21
- </div>
45
+ </div>
22
46
 
23
- <!-- Search -->
24
- <div class="w-full sm:w-auto">
25
- <div class="relative rounded-md shadow-sm">
26
- <label for="search" class="sr-only">Search</label>
27
- <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
28
- <svg class="h-5 w-5 text-slate-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
29
- <path fill-rule="evenodd" d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z" clip-rule="evenodd" />
30
- </svg>
47
+ <!-- Right: Search -->
48
+ <% if @grid.searchable? %>
49
+ <div class="w-full sm:w-auto">
50
+ <label for="search" class="sr-only">Search</label>
51
+ <div class="relative rounded-md shadow-sm">
52
+ <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
53
+ <svg class="h-5 w-5 text-slate-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
54
+ <path fill-rule="evenodd" d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z" clip-rule="evenodd" />
55
+ </svg>
56
+ </div>
57
+ <%= text_field_tag :q, params[:q], placeholder: "Search...",
58
+ class: "block w-full rounded-md border-0 py-1.5 pl-10 text-slate-900 ring-1 ring-inset ring-slate-300 placeholder:text-slate-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 dark:bg-slate-800 dark:text-white dark:ring-slate-600 dark:placeholder-slate-500",
59
+ data: { action: "input->power-grid-table#search" },
60
+ form: "power_grid_form_#{request.path.parameterize}"
61
+ %>
62
+ </div>
31
63
  </div>
32
- <%= text_field_tag :q, params[:q], placeholder: "Search...",
33
- class: "block w-full rounded-md border-0 py-1.5 pl-10 text-slate-900 ring-1 ring-inset ring-slate-300 placeholder:text-slate-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 dark:bg-slate-800 dark:text-white dark:ring-slate-600 dark:placeholder-slate-500",
34
- data: { action: "input->power-grid-table#search" },
35
- form: "power_grid_form_#{request.path.parameterize}"
36
- %>
37
- </div>
64
+ <% end %>
65
+
38
66
  </div>
39
67
  </div>
40
68
 
@@ -101,6 +129,7 @@
101
129
  </div>
102
130
  <div>
103
131
  <!-- Numbered Pagination Controls -->
132
+ <% if @grid.total_pages > 1 %>
104
133
  <nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
105
134
  <% if @grid.current_page > 1 %>
106
135
  <%= link_to "Previous", request.params.merge(page: @grid.current_page - 1), class: "relative inline-flex items-center rounded-l-md px-2 py-2 text-slate-400 ring-1 ring-inset ring-slate-300 hover:bg-slate-50 focus:z-20 focus:outline-offset-0 dark:ring-slate-600 dark:hover:bg-slate-800", data: { turbo_action: "advance" } %>
@@ -120,6 +149,7 @@
120
149
  <%= link_to "Next", request.params.merge(page: @grid.current_page + 1), class: "relative inline-flex items-center rounded-r-md px-2 py-2 text-slate-400 ring-1 ring-inset ring-slate-300 hover:bg-slate-50 focus:z-20 focus:outline-offset-0 dark:ring-slate-600 dark:hover:bg-slate-800", data: { turbo_action: "advance" } %>
121
150
  <% end %>
122
151
  </nav>
152
+ <% end %>
123
153
  </div>
124
154
  </div>
125
155
  </div>
@@ -30,8 +30,8 @@ module PowerGrid
30
30
 
31
31
  attr_reader :params, :initial_scope
32
32
 
33
- def initialize(params = {}, initial_scope: nil)
34
- @params = params
33
+ def initialize(params = {}, initial_scope: nil, **options)
34
+ @params = params.merge(options)
35
35
  @initial_scope = initial_scope
36
36
  end
37
37
 
@@ -39,7 +39,7 @@ module PowerGrid
39
39
  @records ||= begin
40
40
  scope = @initial_scope || instance_eval(&self.class.defined_scope)
41
41
  scope = apply_includes(scope)
42
- scope = apply_includes(scope)
42
+ scope = apply_filters(scope)
43
43
  scope = apply_search(scope)
44
44
  scope = apply_sort(scope)
45
45
 
@@ -57,6 +57,10 @@ module PowerGrid
57
57
  @total_count
58
58
  end
59
59
 
60
+ def searchable?
61
+ self.class.defined_columns.any? { |_, opts| opts[:searchable] }
62
+ end
63
+
60
64
  def current_page
61
65
  (params[:page] || 1).to_i
62
66
  end
@@ -150,5 +154,21 @@ module PowerGrid
150
154
  scope.order(sort_expr => direction)
151
155
  end
152
156
 
157
+ def apply_filters(scope)
158
+ self.class.defined_filters.each do |name, options|
159
+ value = params[name]
160
+ next if value.blank?
161
+
162
+ # Basic equality filter for now.
163
+ # TODO: Support blocks/procs for custom filtering
164
+
165
+ # If sql_expression option exists, use that
166
+ col_name = options[:sql_expression] || name
167
+
168
+ scope = scope.where(col_name => value)
169
+ end
170
+ scope
171
+ end
172
+
153
173
  end
154
174
  end
@@ -1,3 +1,3 @@
1
1
  module PowerGrid
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: power_grid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bhavin Nandani
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-12-12 00:00:00.000000000 Z
11
+ date: 2025-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails