mensa 0.3.2 → 0.3.4

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +5 -21
  4. data/README.md +25 -42
  5. data/app/components/mensa/add_filter/component.html.erb +31 -0
  6. data/app/components/mensa/cell/component.html.erb +1 -0
  7. data/app/components/mensa/column_customizer/component.html.erb +31 -0
  8. data/app/components/mensa/control_bar/component.html.erb +56 -0
  9. data/app/components/mensa/empty_state/component.html.erb +10 -0
  10. data/app/components/mensa/filter_pill/component.html.erb +20 -0
  11. data/app/components/mensa/filter_pill_list/component.html.erb +30 -0
  12. data/app/components/mensa/header/component.html.erb +12 -0
  13. data/app/components/mensa/row_action/component.html.erb +10 -0
  14. data/app/components/mensa/search/component.html.erb +26 -0
  15. data/app/components/mensa/table/component.html.erb +25 -0
  16. data/app/components/mensa/table_row/component.html.erb +18 -0
  17. data/app/components/mensa/view/component.html.erb +51 -0
  18. data/app/components/mensa/views/component.html.erb +74 -0
  19. data/app/tables/mensa/action.rb +8 -1
  20. data/app/views/mensa/exports/_badge.html.erb +6 -0
  21. data/app/views/mensa/exports/_dialog.html.erb +52 -0
  22. data/app/views/mensa/exports/_list.html.erb +32 -0
  23. data/app/views/mensa/tables/filters/show.turbo_stream.erb +58 -0
  24. data/app/views/mensa/tables/show.html.erb +5 -0
  25. data/app/views/mensa/tables/show.turbo_stream.erb +7 -0
  26. data/app/views/mensa/tables/views/create.turbo_stream.erb +11 -0
  27. data/app/views/mensa/tables/views/destroy.turbo_stream.erb +11 -0
  28. data/app/views/mensa/tables/views/update.turbo_stream.erb +11 -0
  29. data/lib/generators/mensa/table_generator.rb +15 -0
  30. data/lib/generators/mensa/templates/config/initializers/mensa.rb +4 -5
  31. data/lib/generators/mensa/templates/table.rb.tt +18 -0
  32. data/lib/mensa/engine.rb +0 -1
  33. data/lib/mensa/version.rb +1 -1
  34. data/mensa.gemspec +2 -4
  35. metadata +29 -54
  36. data/app/components/mensa/add_filter/component.html.slim +0 -14
  37. data/app/components/mensa/cell/component.html.slim +0 -1
  38. data/app/components/mensa/column_customizer/component.html.slim +0 -14
  39. data/app/components/mensa/control_bar/component.html.slim +0 -43
  40. data/app/components/mensa/empty_state/component.html.slim +0 -7
  41. data/app/components/mensa/filter_pill/component.html.slim +0 -9
  42. data/app/components/mensa/filter_pill_list/component.html.slim +0 -11
  43. data/app/components/mensa/header/component.html.slim +0 -8
  44. data/app/components/mensa/row_action/component.html.slim +0 -6
  45. data/app/components/mensa/search/component.html.slim +0 -21
  46. data/app/components/mensa/table/component.html.slim +0 -10
  47. data/app/components/mensa/table_row/component.html.slim +0 -11
  48. data/app/components/mensa/view/component.html.slim +0 -30
  49. data/app/components/mensa/views/component.html.slim +0 -52
  50. data/app/views/mensa/exports/_badge.html.slim +0 -5
  51. data/app/views/mensa/exports/_dialog.html.slim +0 -42
  52. data/app/views/mensa/exports/_list.html.slim +0 -29
  53. data/app/views/mensa/tables/filters/show.turbo_stream.slim +0 -36
  54. data/app/views/mensa/tables/show.html.slim +0 -4
  55. data/app/views/mensa/tables/show.turbo_stream.slim +0 -5
  56. data/app/views/mensa/tables/views/create.turbo_stream.slim +0 -11
  57. data/app/views/mensa/tables/views/destroy.turbo_stream.slim +0 -11
  58. data/app/views/mensa/tables/views/update.turbo_stream.slim +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56a69b51d2f62c342f16b42fc0c0d77fc69101e493486eafea8c89cc358bfd9a
4
- data.tar.gz: 072b02f3d2ebff3ebcd310643b7be1ccb199024771bdb346fd92be4faa9b6ab0
3
+ metadata.gz: 194b34ee31bebddc3962cc66e5c789e5369f828eb6087f67f72b54aba97f65d8
4
+ data.tar.gz: 1ead92c4d986f5e69c3d5745fcee27541f8205bf0106bd25f757b7603cdc117f
5
5
  SHA512:
6
- metadata.gz: 4a32e5e1ed6b6a195d8ad4913d6497082e7ac72721bd18410b3135ad502eeef74ae7cf0e91bee2dcc0fae41f3be85018e181bad3f16382d5d2b6bf8698fda70a
7
- data.tar.gz: a6e26eeecd788492da78499a985fc107697bc7916d6562708aa32b3c58a1c681ed2478ee91070db5df5372628d5f1c77d27a0b482a1f9076187b8e4e66e5431d
6
+ metadata.gz: f5c078859d1c6214b8b65ab36fd077a2c36e2f5b50a69efd0dc20621d6373977be10ed543bc68add8b81338b4322903c3c305a15a0bd47c8ea906d77953c2a9d
7
+ data.tar.gz: 6e68ccdd3ffea1ef460876f61a9d624a8d7de198addad7c712bfac67eac1cc08fbe0874221ba76f241ce5d47c8dec0b09c7950f058865ee232ca540868bea95d
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ gem "sprockets-rails"
10
10
  gem "pry"
11
11
  gem "capybara", "~> 3.40"
12
12
  gem "selenium-webdriver", "~> 4.17"
13
- gem "slim", "~> 5.2"
13
+
14
14
  gem "debug"
15
15
  gem "overmind", require: false
16
16
  gem "rack-mini-profiler"
data/Gemfile.lock CHANGED
@@ -1,14 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mensa (0.3.1)
4
+ mensa (0.3.3)
5
5
  csv
6
6
  importmap-rails
7
7
  pagy (>= 43)
8
8
  pg (>= 1.6)
9
9
  rails (>= 7.1)
10
10
  rubyzip (>= 1.2.2)
11
- slim
12
11
  stimulus-rails
13
12
  tailwindcss-rails (~> 3.3)
14
13
  textacular (>= 5)
@@ -153,7 +152,7 @@ GEM
153
152
  minitest (6.0.6)
154
153
  drb (~> 2.0)
155
154
  prism (~> 1.5)
156
- net-imap (0.6.4)
155
+ net-imap (0.6.4.1)
157
156
  date
158
157
  net-protocol
159
158
  net-pop (0.1.2)
@@ -184,7 +183,7 @@ GEM
184
183
  overmind (2.5.1-arm-linux)
185
184
  overmind (2.5.1-arm64-darwin)
186
185
  overmind (2.5.1-x86_64-darwin)
187
- pagy (43.5.5)
186
+ pagy (43.5.6)
188
187
  json
189
188
  uri
190
189
  yaml
@@ -307,9 +306,6 @@ GEM
307
306
  rexml (~> 3.2, >= 3.2.5)
308
307
  rubyzip (>= 1.2.2, < 4.0)
309
308
  websocket (~> 1.0)
310
- slim (5.2.1)
311
- temple (~> 0.10.0)
312
- tilt (>= 2.1.0)
313
309
  sprockets (4.2.2)
314
310
  concurrent-ruby (~> 1.0)
315
311
  logger
@@ -318,14 +314,6 @@ GEM
318
314
  actionpack (>= 6.1)
319
315
  activesupport (>= 6.1)
320
316
  sprockets (>= 3.0.0)
321
- sqlite3 (2.9.4-aarch64-linux-gnu)
322
- sqlite3 (2.9.4-aarch64-linux-musl)
323
- sqlite3 (2.9.4-arm-linux-gnu)
324
- sqlite3 (2.9.4-arm-linux-musl)
325
- sqlite3 (2.9.4-arm64-darwin)
326
- sqlite3 (2.9.4-x86_64-darwin)
327
- sqlite3 (2.9.4-x86_64-linux-gnu)
328
- sqlite3 (2.9.4-x86_64-linux-musl)
329
317
  standard (1.54.0)
330
318
  language_server-protocol (~> 3.17.0.2)
331
319
  lint_roller (~> 1.0)
@@ -349,11 +337,9 @@ GEM
349
337
  tailwindcss-ruby (3.4.19-arm64-darwin)
350
338
  tailwindcss-ruby (3.4.19-x86_64-darwin)
351
339
  tailwindcss-ruby (3.4.19-x86_64-linux)
352
- temple (0.10.4)
353
340
  textacular (5.7.0)
354
341
  activerecord (>= 5.0)
355
342
  thor (1.5.0)
356
- tilt (2.7.0)
357
343
  timeout (0.6.1)
358
344
  tsort (0.2.0)
359
345
  turbo-rails (2.0.23)
@@ -366,12 +352,12 @@ GEM
366
352
  unicode-emoji (4.2.0)
367
353
  uri (1.1.1)
368
354
  useragent (0.16.11)
369
- view_component (3.24.0)
355
+ view_component (3.25.0)
370
356
  activesupport (>= 5.2.0, < 8.2)
371
357
  concurrent-ruby (~> 1)
372
358
  method_source (~> 1.0)
373
359
  websocket (1.2.11)
374
- websocket-driver (0.8.0)
360
+ websocket-driver (0.8.1)
375
361
  base64
376
362
  websocket-extensions (>= 0.1.0)
377
363
  websocket-extensions (0.1.5)
@@ -404,9 +390,7 @@ DEPENDENCIES
404
390
  ruby-lsp
405
391
  ruby-lsp-rails
406
392
  selenium-webdriver (~> 4.17)
407
- slim (~> 5.2)
408
393
  sprockets-rails
409
- sqlite3 (~> 2.8)
410
394
  standard
411
395
 
412
396
  BUNDLED WITH
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Mensa
2
2
 
3
3
  Fast and awesome tables, with pagination, sorting, filtering, batch processing, column hiding, column ordering and custom views.
4
+ Due to search, it only works with postgresql at the moment.
4
5
 
5
6
  ![table](./docs/table.png)
6
7
  ![filters](./docs/filters.png)
@@ -52,16 +53,7 @@ class UserTable < ApplicationTable
52
53
  order name: :desc
53
54
 
54
55
  column(:name) do
55
- attribute :name # Optional, we can deduct this from the column name
56
- sortable true
57
- sanitize true
58
- internal false
59
- visible true
60
- filter do
61
- collection -> { }
62
- scope -> { where(name: ...) }
63
- end
64
- operators [:is, :isnt] # Optional, mensa tries to deduce this from the column information
56
+ filter
65
57
  end
66
58
 
67
59
  column(:nr_of_roles) do
@@ -73,6 +65,8 @@ class UserTable < ApplicationTable
73
65
  title "Delete row"
74
66
  link { |user| user_path(user) }
75
67
  icon "fa-regular fa-trash"
68
+ # You could also give it a block, which takes the record as an argument, to choose icons dynamically
69
+ # icon { |product| product.inventory? ? "fal fa-shelves" : "fal fa-shelves-empty" }
76
70
  link_attributes data: {"turbo-confirm": "Are you sure you want to delete the user?", "turbo-method": :delete}
77
71
  show ->(user) { true }
78
72
  end
@@ -112,17 +106,14 @@ end
112
106
 
113
107
  You can show your tables on the page using the following:
114
108
 
115
- ```slim
116
- = table :users
109
+ ```erb
110
+ <%= table :users %>
117
111
  ```
118
112
 
119
113
  #### Custom views
120
114
 
121
115
  Custom views are views not defined by the developer (SystemViews) but by the end-user by adding/removing filters.
122
-
123
- Initial support for custom-views is there, but pretty rudimentary:
124
-
125
- `Mensa::TableView.create(table: "users", name: "Guests", config: {filters: {role: {value: "guest"}}})`
116
+ When you enable these, they are stored in the database and can be used across sessions, by the user who created them.
126
117
 
127
118
  ### Fast
128
119
 
@@ -140,42 +131,27 @@ end
140
131
  ### Coding
141
132
 
142
133
  - Checkout this repo
143
- - Setup your direnv, add the following to your `.envrc`:
134
+ - Setup your direnv, add the following to your `mise.toml`:
144
135
 
145
136
  ```
146
- export BUNDLE_RUBYGEMS__PKG__GITHUB__COM=ghp_xxxxxxw
147
- export RBENV_VERSION=$(cat .ruby-version)
137
+ [tools]
138
+ node = "24"
139
+ ruby = "3.4.7"
140
+
141
+ [env]
142
+ RUBY_VERSION="3.4.7"
148
143
  ```
149
144
 
150
145
  - Run `direnv allow`
151
-
152
- If you use devcontainers:
153
- - Open with Visual Studio Code (or with any other editor) and reopen in container.
154
- - Run `bin/overmind s`
155
-
156
- If you're not using devcontainers:
157
- - Run `bin/overmind s`
146
+ - Run `overmind s`
158
147
 
159
148
  ### Docs
160
149
 
161
150
  Using the following in your view will render Mensa::Table::Component
162
- ```slim
163
- = table :users
151
+ ```erb
152
+ <%= table :users %>
164
153
  ```
165
154
 
166
- The Mensa::Table::Component will render:
167
- - Mensa::Search::Component
168
- - Mensa::FilterPillList::Component
169
- - Mensa::FilterPill::Component
170
- - Mensa::AddFilter::Component
171
- - Mensa::Views::Component
172
- - renders a views list
173
- - Mensa::ControlBar::Component
174
- - search icon
175
- - filter icon
176
- - export icon
177
- - turbo-frame with the actual table you see (which is rendered by Mensa::View::Component)
178
-
179
155
  ## Installation
180
156
 
181
157
  Add this line to your application's Gemfile:
@@ -199,7 +175,14 @@ $ gem install mensa
199
175
  Always use `bundle` to install the gem. Next use the install generator to install migrations, add an initializer and do other setup:
200
176
 
201
177
  ```bash
202
- $ bin/rails g mensa:install
178
+ $ rails g mensa:install
179
+ $ rails mensa:install:migrations
180
+ ```
181
+
182
+ Next you can run the generator to generate a table:
183
+
184
+ ```bash
185
+ $ rails g mensa:table:generate <model_name>
203
186
  ```
204
187
 
205
188
  ### Exports
@@ -0,0 +1,31 @@
1
+ <div class="mensa-table__add_filter"
2
+ data-controller="mensa-add-filter"
3
+ data-mensa-add-filter-mensa-filter-pill-list-outlet="#mensa-filter-pill-list-<%= table.table_id %>"
4
+ data-mensa-add-filter-operator-labels-value="<%= operator_labels.to_json %>">
5
+ <button class="mensa-table__add_filter__trigger"
6
+ type="button"
7
+ title="<%= t("mensa.add_filter.add", default: "Add filter") %>"
8
+ data-action="mensa-add-filter#openAllColumns">
9
+ <i class="fa-solid fa-circle-plus"></i>
10
+ </button>
11
+
12
+ <ul class="hidden fixed z-50 max-h-96 overflow-auto rounded-lg bg-white p-2 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-800 sm:text-sm"
13
+ data-mensa-add-filter-target="filterList">
14
+ <% table.columns.select(&:filter?).each do |column| %>
15
+ <li class="text-gray-900 hover:bg-gray-100 relative flex cursor-default select-none items-center gap-2 rounded-md px-3 py-2 dark:text-gray-300 dark:hover:bg-gray-700"
16
+ data-mensa-add-filter-target="filterListItem"
17
+ data-action="click->mensa-add-filter#selectColumn mouseenter->mensa-add-filter#columnItemHovered"
18
+ data-filter-column-name="<%= column.name %>">
19
+ <div class="label block flex-1 truncate font-normal"><%= column.human_name %></div>
20
+ <div class="check hidden flex items-center text-primary-600">
21
+ <div class="fal fa-check"></div>
22
+ </div>
23
+ <span class="mensa-table__add_filter__enter-hint">↵ Enter</span>
24
+ </li>
25
+ <% end %>
26
+ </ul>
27
+
28
+ <div class="hidden mensa-table__add_filter__popover_container"
29
+ data-mensa-add-filter-target="valuePopover"
30
+ id="mensa-filter-pill-value-<%= SecureRandom.base36 %>"></div>
31
+ </div>
@@ -0,0 +1 @@
1
+ <td><%= cell.render(:html) %></td>
@@ -0,0 +1,31 @@
1
+ <div class="relative"
2
+ data-controller="mensa-column-customizer"
3
+ data-mensa-column-customizer-table-name-value="<%= table.name %>"
4
+ data-mensa-column-customizer-turbo-frame-id-value="<%= table.table_id %>"
5
+ data-mensa-column-customizer-mensa-table-outlet="#table-<%= table.table_id %>">
6
+ <button class="mensa-table__control_bar__button" type="button" data-action="click->mensa-column-customizer#toggle">
7
+ <i class="<%= Mensa.config.icons[:control_bar_edit] %>"></i>
8
+ </button>
9
+ <div class="mensa-table__column_customizer__popover hidden" data-mensa-column-customizer-target="popover">
10
+ <p class="mensa-table__column_customizer__heading">Columns</p>
11
+ <ul>
12
+ <% table.columns.reject(&:internal?).each do |column| %>
13
+ <li class="mensa-table__column_customizer__row"
14
+ data-mensa-column-customizer-target="columnRow"
15
+ data-column-name="<%= column.name %>"
16
+ data-visible="<%= column.visible?.to_s %>"
17
+ draggable="true"
18
+ data-action="dragstart->mensa-column-customizer#dragStart dragover->mensa-column-customizer#dragOver drop->mensa-column-customizer#drop dragend->mensa-column-customizer#dragEnd">
19
+ <i class="mensa-table__column_customizer__handle fa-solid fa-grip-vertical"></i>
20
+ <span class="mensa-table__column_customizer__name<%= !column.visible? ? " mensa-table__column_customizer__name--hidden" : "" %>">
21
+ <%= column.human_name %>
22
+ </span>
23
+ <button class="mensa-table__column_customizer__visibility" type="button" data-action="click->mensa-column-customizer#toggleVisibility">
24
+ <i class="fa-solid fa-eye"></i>
25
+ <i class="fa-solid fa-eye-slash"></i>
26
+ </button>
27
+ </li>
28
+ <% end %>
29
+ </ul>
30
+ </div>
31
+ </div>
@@ -0,0 +1,56 @@
1
+ <div class="mensa-table__control_bar" data-mensa-table-target="controlBar">
2
+ <div class="flex items-center gap-1 py-0">
3
+ <% if view_columns_ordering? %>
4
+ <%= render Mensa::ColumnCustomizer::Component.new(table: table) %>
5
+ <% end %>
6
+
7
+ <div class="mensa-table__save-reset hidden" data-mensa-table-target="saveResetButtons">
8
+ <button class="mensa-table__control_bar__button" type="button" title="<%= t(".reset", default: "Reset") %>" data-action="mensa-table#cancelFiltersAndSearch">
9
+ <i class="fa-solid fa-rotate-left"></i>
10
+ </button>
11
+ <% if table.current_user && table.supports_custom_views? %>
12
+ <div class="relative">
13
+ <button class="mensa-table__control_bar__button hidden" type="button" data-mensa-table-target="saveSimple" data-action="mensa-table#saveAsNewView">
14
+ <%= t(".save", default: "Save") %>
15
+ </button>
16
+ <button class="mensa-table__control_bar__button hidden" type="button" data-mensa-table-target="saveSplit" data-action="mensa-table#toggleSaveDropdown">
17
+ <%= t(".save", default: "Save") %>
18
+ <i class="fa-solid fa-chevron-down text-xs"></i>
19
+ </button>
20
+ <ul class="mensa-table__control_bar__save-dropdown hidden" data-mensa-table-target="saveDropdown">
21
+ <li>
22
+ <button class="mensa-table__control_bar__save-dropdown-item" type="button" data-action="mensa-table#updateCurrentViewAction">
23
+ <%= t(".update_view", default: "Update view") %>
24
+ </button>
25
+ </li>
26
+ <li>
27
+ <button class="mensa-table__control_bar__save-dropdown-item" type="button" data-action="mensa-table#saveAsNewView">
28
+ <%= t(".save_as_new_view", default: "Save as new view") %>
29
+ </button>
30
+ </li>
31
+ </ul>
32
+ </div>
33
+ <% else %>
34
+ <button class="mensa-table__control_bar__button" type="button" data-action="mensa-table#saveAsNewView">
35
+ <%= t(".save", default: "Save") %>
36
+ </button>
37
+ <% end %>
38
+ </div>
39
+
40
+ <button class="mensa-table__control_bar__button hidden" type="button" data-mensa-table-target="eyeButton" data-action="click->mensa-table#toggleViewFilters">
41
+ <i class="fa-solid fa-eye"></i>
42
+ </button>
43
+
44
+ <% if table.exportable? %>
45
+ <button class="mensa-table__control_bar__button relative" type="button" data-action="mensa-table#export">
46
+ <i data-mensa-table-target="exportIcon" class="<%= Mensa.config.icons[:control_bar_export] %>"></i>
47
+ <%= helpers.render partial: "mensa/exports/badge", locals: {table_name: table.name, user: table.current_user} %>
48
+ </button>
49
+ <% end %>
50
+ </div>
51
+
52
+ <% if table.exportable? %>
53
+ <%= helpers.turbo_stream_from Mensa::Export.stream_name(table.name, table.current_user) %>
54
+ <%= helpers.render partial: "mensa/exports/dialog", locals: {table: table} %>
55
+ <% end %>
56
+ </div>
@@ -0,0 +1,10 @@
1
+ <div class="mensa-empty-state">
2
+ <div class="mensa-empty-state__icon">
3
+ <i class="<%= Mensa.config.icons[:search] %>"></i>
4
+ </div>
5
+ <h3 class="mensa-empty-state__title"><%= t("mensa.empty_state.title", model: model_name_plural) %></h3>
6
+ <p class="mensa-empty-state__subtitle"><%= t("mensa.empty_state.subtitle") %></p>
7
+ <button class="mensa-empty-state__button" type="button" data-action="click->mensa-table#cancelFiltersAndSearch">
8
+ <%= t("mensa.empty_state.clear_button") %>
9
+ </button>
10
+ </div>
@@ -0,0 +1,20 @@
1
+ <% formatted_value = filter.value.is_a?(Array) ? filter.value.join(", ") : filter.value %>
2
+ <div class="mensa-filter-pill"
3
+ data-controller="mensa-filter-pill"
4
+ data-mensa-filter-pill-mensa-filter-pill-list-outlet="#mensa-filter-pill-list-<%= filter.table.table_id %>"
5
+ data-mensa-filter-pill-column-name-value="<%= filter.column.name %>"
6
+ data-mensa-filter-pill-value-value="<%= filter.operator_with_value? ? (filter.value.is_a?(Array) ? filter.value.to_json : filter.value) : nil %>"
7
+ data-mensa-filter-pill-operator-value="<%= filter.operator %>"
8
+ data-mensa-filter-pill-operator-without-value-value="<%= "true" unless filter.operator_with_value? %>"
9
+ data-view-filter="<%= "true" if view_filter? %>">
10
+ <button class="mensa-filter-pill__chip" type="button" data-action="click->mensa-filter-pill#edit">
11
+ <span class="mensa-filter-pill__column"><%= filter.column.human_name %></span>
12
+ <span class="mensa-filter-pill__operator"><%= filter.operator_label %></span>
13
+ <% if formatted_value.present? && filter.operator_with_value? %>
14
+ <span class="mensa-filter-pill__value"><%= formatted_value %></span>
15
+ <% end %>
16
+ </button>
17
+ <button class="mensa-filter-pill__remove" type="button" title="Remove filter" data-action="click->mensa-filter-pill#remove">
18
+ <i class="fa-solid fa-xmark"></i>
19
+ </button>
20
+ </div>
@@ -0,0 +1,30 @@
1
+ <% has_filterable_columns = table.columns.any?(&:filter?) %>
2
+ <div class="mensa-table__search-bar"
3
+ id="mensa-filter-pill-list-<%= table.table_id %>"
4
+ data-controller="mensa-filter-pill-list"
5
+ data-mensa-table-target="filterList"
6
+ data-mensa-filter-pill-list-table-name-value="<%= table.name %>"
7
+ data-mensa-filter-pill-list-mensa-table-outlet=".mensa-table#table-<%= table.table_id %>"
8
+ data-mensa-filter-pill-list-mensa-filter-pill-outlet=".mensa-filter-pill"
9
+ data-mensa-filter-pill-list-mensa-add-filter-outlet="[data-controller=mensa-add-filter]">
10
+ <div class="mensa-table__search-bar__pills-area">
11
+ <%= render Mensa::FilterPill::Component.with_collection(table.active_filters) %>
12
+ <% if has_filterable_columns %>
13
+ <%= render Mensa::AddFilter::Component.new(table: table) %>
14
+ <% end %>
15
+ <div class="mensa-table__search-bar__input-wrapper">
16
+ <input class="mensa-table__search-bar__input"
17
+ type="text"
18
+ name="search_query"
19
+ autocomplete="off"
20
+ placeholder="<%= t(has_filterable_columns ? ".search" : ".search_only") %>"
21
+ data-mensa-filter-pill-list-target="searchInput"
22
+ data-action="input->mensa-filter-pill-list#monitorSearch keydown.enter->mensa-filter-pill-list#search keydown.esc->mensa-filter-pill-list#resetSearch focus->mensa-filter-pill-list#searchFocused keydown.down->mensa-filter-pill-list#navigateDown keydown.up->mensa-filter-pill-list#navigateUp"
23
+ value="<%= params[:query] %>">
24
+ <i class="mensa-table__search-bar__search-icon <%= Mensa.config.icons[:search] %>"></i>
25
+ </div>
26
+ </div>
27
+ <button class="mensa-table__search-bar__clear hidden" type="button" data-mensa-filter-pill-list-target="resetSearchButton" data-action="mensa-filter-pill-list#resetSearch">
28
+ <i class="fas fa-xmark"></i>
29
+ </button>
30
+ </div>
@@ -0,0 +1,12 @@
1
+ <th>
2
+ <% if column.sortable? %>
3
+ <%= link_to table.path(order: {column.name => column.next_sort_direction}, turbo_frame_id: table.table_id), "data-turbo-frame": "_self", class: "order cursor-pointer" do %>
4
+ <span><%= column.human_name %></span>
5
+ <i class="<%= Mensa.config.icons["order_indicator#{column.sort_direction.to_s.present? ? "_#{column.sort_direction}" : ""}".to_sym] %>"></i>
6
+ <% end %>
7
+ <% else %>
8
+ <div class="container">
9
+ <div class="title"><%= column.human_name %></div>
10
+ </div>
11
+ <% end %>
12
+ </th>
@@ -0,0 +1,10 @@
1
+ <% if action.show.call(row.record) %>
2
+ <%= link_to(action.link ? table.original_view_context.instance_exec(row.record, &action.link) : "", {class: "action", title: action.title}.merge(action.link_attributes || {})) do %>
3
+
4
+ <% if icon = action.icon(row.record) %>
5
+ <i class="fa <%= icon %>"></i>
6
+ <% else %>
7
+ <%= name %>
8
+ <% end %>
9
+ <% end %>
10
+ <% end %>
@@ -0,0 +1,26 @@
1
+ <% if table.current_user %>
2
+ <dialog class="mensa-table__save-view-dialog" data-mensa-table-target="saveViewDialog" data-action="click->mensa-table#saveViewDialogBackdrop">
3
+ <form class="mensa-table__save-view-dialog__form" data-action="submit->mensa-table#confirmSaveView">
4
+ <header class="mensa-table__save-view-dialog__header">
5
+ <h2 class="mensa-table__save-view-dialog__title"><%= t(".save_view_title", default: "Save view") %></h2>
6
+ <p class="mensa-table__save-view-dialog__subtitle"><%= t(".save_view_subtitle", default: "Save the current filters, ordering and search as a reusable view.") %></p>
7
+ </header>
8
+ <label class="mensa-table__save-view-dialog__field">
9
+ <span class="mensa-table__save-view-dialog__label"><%= t(".view_name", default: "Name") %></span>
10
+ <input class="mensa-table__save-view-dialog__input" type="text" required placeholder="<%= t(".view_name_placeholder", default: "e.g. Active customers") %>" data-mensa-table-target="saveViewName">
11
+ </label>
12
+ <label class="mensa-table__save-view-dialog__field">
13
+ <span class="mensa-table__save-view-dialog__label"><%= t(".view_description", default: "Description") %></span>
14
+ <textarea class="mensa-table__save-view-dialog__textarea" rows="3" placeholder="<%= t(".view_description_placeholder", default: "Optional notes about this view") %>" data-mensa-table-target="saveViewDescription"></textarea>
15
+ </label>
16
+ <div class="mensa-table__save-view-dialog__actions">
17
+ <button class="mensa-table__save-view-dialog__button mensa-table__save-view-dialog__button--secondary" type="button" data-action="mensa-table#cancelSaveView">
18
+ <%= t(".cancel") %>
19
+ </button>
20
+ <button class="mensa-table__save-view-dialog__button mensa-table__save-view-dialog__button--primary" type="submit">
21
+ <%= t(".save") %>
22
+ </button>
23
+ </div>
24
+ </form>
25
+ </dialog>
26
+ <% end %>
@@ -0,0 +1,25 @@
1
+ <div class="mensa-table"
2
+ id="table-<%= table.table_id %>"
3
+ data-mensa-table-supports-views-value="<%= table.supports_views? %>"
4
+ data-mensa-table-table-url-value="<%= helpers.mensa.table_url(table.name, {turbo_frame_id: table.table_id}.merge(params)) %>"
5
+ data-mensa-table-save-view-url-value="<%= helpers.mensa.table_views_path(table.name) %>"
6
+ data-mensa-table-views-url-value="<%= helpers.mensa.table_views_path(table.name) %>"
7
+ data-mensa-table-exports-url-value="<%= helpers.mensa.table_exports_path(table.name) %>"
8
+ data-controller="mensa-table"
9
+ data-mensa-table-mensa-filter-pill-outlet="[data-controller='mensa-filter-pill']"
10
+ data-mensa-table-mensa-filter-pill-list-outlet="#mensa-filter-pill-list-<%= table.table_id %>"
11
+ data-mensa-table-mensa-column-customizer-outlet="[data-controller='mensa-column-customizer']">
12
+ <div class="mensa-table__toolbar">
13
+ <div class="mensa-table__search-container">
14
+ <% if table.supports_views? && table.show_header? %>
15
+ <%= render Mensa::Views::Component.new(table: table) %>
16
+ <% end %>
17
+ <div class="flex min-w-0 flex-1" id="filters-<%= table.table_id %>">
18
+ <%= render Mensa::FilterPillList::Component.new(table: table) %>
19
+ </div>
20
+ </div>
21
+ <%= render Mensa::ControlBar::Component.new(table: table) %>
22
+ </div>
23
+ <%= render Mensa::Search::Component.new(table: table) %>
24
+ <turbo-frame id="<%= table.table_id %>" target="_top" data-mensa-table-target="turboFrame" data-turbo-permanent=""></turbo-frame>
25
+ </div>
@@ -0,0 +1,18 @@
1
+ <%= content_tag :tr, **row.link_attributes do %>
2
+ <% if table.batch_actions? %>
3
+ <td class="mensa-table__checkbox-col" data-action="click->mensa-selection#stopPropagation">
4
+ <input class="mensa-table__select-all" type="checkbox" value="<%= row.record.id %>" data-action="change->mensa-selection#toggleRow" data-mensa-selection-target="rowCheckbox">
5
+ </td>
6
+ <% end %>
7
+ <% if table.actions? && Mensa.config.row_actions_position == :front %>
8
+ <td class="actions">
9
+ <%= render(Mensa::RowAction::Component.with_collection(table.actions, row: row, table: table)) %>
10
+ </td>
11
+ <% end %>
12
+ <%= render(Mensa::Cell::Component.with_collection(table.display_columns, row: row)) %>
13
+ <% if table.actions? && Mensa.config.row_actions_position == :back %>
14
+ <td class="actions">
15
+ <%= render(Mensa::RowAction::Component.with_collection(table.actions, row: row, table: table)) %>
16
+ </td>
17
+ <% end %>
18
+ <% end %>
@@ -0,0 +1,51 @@
1
+ <div class="overflow-y-auto relative"
2
+ data-mensa-table-target="view"
3
+ data-controller="mensa-selection"
4
+ data-mensa-selection-batch-url-value="<%= table.batch_actions? ? helpers.mensa.table_batch_actions_path(table.name) : "" %>">
5
+ <% if table.batch_actions? %>
6
+ <div class="mensa-batch-bar hidden" data-mensa-selection-target="batchBar">
7
+ <div class="mensa-batch-bar__content">
8
+ <input class="mensa-table__select-all" type="checkbox" data-action="click->mensa-selection#deselectAll" data-mensa-selection-target="batchAllCheckbox">
9
+ <span class="mensa-batch-bar__count" data-mensa-selection-target="selectedCount"></span>
10
+ <% table.batch_actions.each do |batch_action| %>
11
+ <button class="mensa-batch-bar__button" type="button" data-action="click->mensa-selection#executeBatch" data-mensa-selection-batch-action-param="<%= batch_action.name %>">
12
+ <%= batch_action.title %>
13
+ </button>
14
+ <% end %>
15
+ </div>
16
+ </div>
17
+ <% end %>
18
+ <table class="w-full">
19
+ <% if table.show_header? %>
20
+ <thead>
21
+ <tr>
22
+ <% if table.batch_actions? %>
23
+ <th class="mensa-table__checkbox-col">
24
+ <div class="container">
25
+ <input class="mensa-table__select-all" type="checkbox" data-action="change->mensa-selection#toggleAll" data-mensa-selection-target="headerCheckbox">
26
+ </div>
27
+ </th>
28
+ <% end %>
29
+ <% if table.actions? && Mensa.config.row_actions_position == :front %>
30
+ <th>Actions</th>
31
+ <% end %>
32
+ <%= render(Mensa::Header::Component.with_collection(table.display_columns, table: table)) %>
33
+ <% if table.actions? && Mensa.config.row_actions_position == :back %>
34
+ <th>Actions</th>
35
+ <% end %>
36
+ </tr>
37
+ </thead>
38
+ <% end %>
39
+ <tbody>
40
+ <%= render(Mensa::TableRow::Component.with_collection(table.rows, table: table)) %>
41
+ </tbody>
42
+ </table>
43
+ <% if table.pagy_details&.count == 0 %>
44
+ <%= render Mensa::EmptyState::Component.new(table: table) %>
45
+ <% elsif table.pagy_details&.last > 1 %>
46
+ <div class="paging">
47
+ <span><%= t("mensa.paging.info", model: model_name_plural, from: table.pagy_details.from, to: table.pagy_details.to, count: table.pagy_details.count) %></span>
48
+ <%== table.pagy_details.series_nav(anchor_string: 'data-turbo-frame="_self"') %>
49
+ </div>
50
+ <% end %>
51
+ </div>