mensa 0.3.1 → 0.3.3

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -2
  3. data/Gemfile.lock +2 -34
  4. data/README.md +18 -44
  5. data/app/components/mensa/add_filter/component.html.erb +31 -0
  6. data/app/components/mensa/add_filter/component_controller.js +0 -1
  7. data/app/components/mensa/application_component.rb +0 -1
  8. data/app/components/mensa/cell/component.html.erb +1 -0
  9. data/app/components/mensa/column_customizer/component.html.erb +31 -0
  10. data/app/components/mensa/control_bar/component.html.erb +56 -0
  11. data/app/components/mensa/empty_state/component.html.erb +10 -0
  12. data/app/components/mensa/filter_pill/component.html.erb +20 -0
  13. data/app/components/mensa/filter_pill_list/component.html.erb +30 -0
  14. data/app/components/mensa/header/component.html.erb +12 -0
  15. data/app/components/mensa/row_action/component.html.erb +9 -0
  16. data/app/components/mensa/search/component.html.erb +26 -0
  17. data/app/components/mensa/selection/component_controller.js +1 -1
  18. data/app/components/mensa/table/component.html.erb +25 -0
  19. data/app/components/mensa/table_row/component.html.erb +18 -0
  20. data/app/components/mensa/view/component.html.erb +51 -0
  21. data/app/components/mensa/views/component.html.erb +74 -0
  22. data/app/helpers/mensa/application_helper.rb +15 -2
  23. data/app/javascript/mensa/controllers/index.js +2 -2
  24. data/app/javascript/mensa/controllers/link_controller.js +44 -0
  25. data/app/tables/mensa/base.rb +0 -6
  26. data/app/tables/mensa/column.rb +1 -10
  27. data/app/tables/mensa/row.rb +1 -1
  28. data/app/views/mensa/exports/_badge.html.erb +6 -0
  29. data/app/views/mensa/exports/_dialog.html.erb +52 -0
  30. data/app/views/mensa/exports/_list.html.erb +32 -0
  31. data/app/views/mensa/tables/filters/show.turbo_stream.erb +58 -0
  32. data/app/views/mensa/tables/show.html.erb +5 -0
  33. data/app/views/mensa/tables/show.turbo_stream.erb +7 -0
  34. data/app/views/mensa/tables/views/create.turbo_stream.erb +11 -0
  35. data/app/views/mensa/tables/views/destroy.turbo_stream.erb +11 -0
  36. data/app/views/mensa/tables/views/update.turbo_stream.erb +11 -0
  37. data/lib/generators/mensa/table_generator.rb +15 -0
  38. data/lib/generators/mensa/templates/config/initializers/mensa.rb +4 -5
  39. data/lib/generators/mensa/templates/table.rb.tt +18 -0
  40. data/lib/mensa/engine.rb +1 -2
  41. data/lib/mensa/version.rb +1 -1
  42. data/mensa.gemspec +3 -4
  43. metadata +43 -53
  44. data/app/components/mensa/add_filter/component.html.slim +0 -14
  45. data/app/components/mensa/cell/component.html.slim +0 -1
  46. data/app/components/mensa/column_customizer/component.html.slim +0 -14
  47. data/app/components/mensa/control_bar/component.html.slim +0 -43
  48. data/app/components/mensa/empty_state/component.html.slim +0 -7
  49. data/app/components/mensa/filter_pill/component.html.slim +0 -9
  50. data/app/components/mensa/filter_pill_list/component.html.slim +0 -11
  51. data/app/components/mensa/header/component.html.slim +0 -8
  52. data/app/components/mensa/row_action/component.html.slim +0 -6
  53. data/app/components/mensa/search/component.html.slim +0 -21
  54. data/app/components/mensa/table/component.html.slim +0 -10
  55. data/app/components/mensa/table_row/component.html.slim +0 -11
  56. data/app/components/mensa/view/component.html.slim +0 -30
  57. data/app/components/mensa/views/component.html.slim +0 -52
  58. data/app/views/mensa/exports/_badge.html.slim +0 -5
  59. data/app/views/mensa/exports/_dialog.html.slim +0 -42
  60. data/app/views/mensa/exports/_list.html.slim +0 -29
  61. data/app/views/mensa/tables/filters/show.turbo_stream.slim +0 -36
  62. data/app/views/mensa/tables/show.html.slim +0 -4
  63. data/app/views/mensa/tables/show.turbo_stream.slim +0 -5
  64. data/app/views/mensa/tables/views/create.turbo_stream.slim +0 -11
  65. data/app/views/mensa/tables/views/destroy.turbo_stream.slim +0 -11
  66. data/app/views/mensa/tables/views/update.turbo_stream.slim +0 -11
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mensa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom de Grunt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-10 00:00:00.000000000 Z
11
+ date: 2026-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -67,47 +67,47 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '43'
69
69
  - !ruby/object:Gem::Dependency
70
- name: textacular
70
+ name: pg
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '5'
75
+ version: '1.6'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '5'
82
+ version: '1.6'
83
83
  - !ruby/object:Gem::Dependency
84
- name: view_component
84
+ name: textacular
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '3.11'
89
+ version: '5'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '3.11'
96
+ version: '5'
97
97
  - !ruby/object:Gem::Dependency
98
- name: slim
98
+ name: view_component
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '3.11'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '3.11'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: tailwindcss-rails
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -164,20 +164,6 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
- - !ruby/object:Gem::Dependency
168
- name: sqlite3
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - "~>"
172
- - !ruby/object:Gem::Version
173
- version: '2.8'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: '2.8'
181
167
  description: Fast and awesome tables, with pagination, sorting, filtering and custom
182
168
  views.
183
169
  email:
@@ -207,55 +193,55 @@ files:
207
193
  - app/assets/images/mensa/.keep
208
194
  - app/assets/stylesheets/mensa/application.css
209
195
  - app/components/mensa/add_filter/component.css
210
- - app/components/mensa/add_filter/component.html.slim
196
+ - app/components/mensa/add_filter/component.html.erb
211
197
  - app/components/mensa/add_filter/component.rb
212
198
  - app/components/mensa/add_filter/component_controller.js
213
199
  - app/components/mensa/application_component.rb
214
200
  - app/components/mensa/cell/component.css
215
- - app/components/mensa/cell/component.html.slim
201
+ - app/components/mensa/cell/component.html.erb
216
202
  - app/components/mensa/cell/component.rb
217
203
  - app/components/mensa/column_customizer/component.css
218
- - app/components/mensa/column_customizer/component.html.slim
204
+ - app/components/mensa/column_customizer/component.html.erb
219
205
  - app/components/mensa/column_customizer/component.rb
220
206
  - app/components/mensa/column_customizer/component_controller.js
221
207
  - app/components/mensa/control_bar/component.css
222
- - app/components/mensa/control_bar/component.html.slim
208
+ - app/components/mensa/control_bar/component.html.erb
223
209
  - app/components/mensa/control_bar/component.rb
224
210
  - app/components/mensa/empty_state/component.css
225
- - app/components/mensa/empty_state/component.html.slim
211
+ - app/components/mensa/empty_state/component.html.erb
226
212
  - app/components/mensa/empty_state/component.rb
227
213
  - app/components/mensa/filter_pill/component.css
228
- - app/components/mensa/filter_pill/component.html.slim
214
+ - app/components/mensa/filter_pill/component.html.erb
229
215
  - app/components/mensa/filter_pill/component.rb
230
216
  - app/components/mensa/filter_pill/component_controller.js
231
217
  - app/components/mensa/filter_pill_list/component.css
232
- - app/components/mensa/filter_pill_list/component.html.slim
218
+ - app/components/mensa/filter_pill_list/component.html.erb
233
219
  - app/components/mensa/filter_pill_list/component.rb
234
220
  - app/components/mensa/filter_pill_list/component_controller.js
235
221
  - app/components/mensa/header/component.css
236
- - app/components/mensa/header/component.html.slim
222
+ - app/components/mensa/header/component.html.erb
237
223
  - app/components/mensa/header/component.rb
238
224
  - app/components/mensa/row_action/component.css
239
- - app/components/mensa/row_action/component.html.slim
225
+ - app/components/mensa/row_action/component.html.erb
240
226
  - app/components/mensa/row_action/component.rb
241
227
  - app/components/mensa/search/component.css
242
- - app/components/mensa/search/component.html.slim
228
+ - app/components/mensa/search/component.html.erb
243
229
  - app/components/mensa/search/component.rb
244
230
  - app/components/mensa/search/component_controller.js
245
231
  - app/components/mensa/selection/component_controller.js
246
232
  - app/components/mensa/table/component.css
247
- - app/components/mensa/table/component.html.slim
233
+ - app/components/mensa/table/component.html.erb
248
234
  - app/components/mensa/table/component.rb
249
235
  - app/components/mensa/table/component_controller.js
250
236
  - app/components/mensa/table_row/component.css
251
- - app/components/mensa/table_row/component.html.slim
237
+ - app/components/mensa/table_row/component.html.erb
252
238
  - app/components/mensa/table_row/component.rb
253
239
  - app/components/mensa/view/component.css
254
- - app/components/mensa/view/component.html.slim
240
+ - app/components/mensa/view/component.html.erb
255
241
  - app/components/mensa/view/component.rb
256
242
  - app/components/mensa/view/paging.css
257
243
  - app/components/mensa/views/component.css
258
- - app/components/mensa/views/component.html.slim
244
+ - app/components/mensa/views/component.html.erb
259
245
  - app/components/mensa/views/component.rb
260
246
  - app/components/mensa/views/component_controller.js
261
247
  - app/controllers/concerns/.keep
@@ -272,6 +258,7 @@ files:
272
258
  - app/javascript/mensa/controllers/application.js
273
259
  - app/javascript/mensa/controllers/application_controller.js
274
260
  - app/javascript/mensa/controllers/index.js
261
+ - app/javascript/mensa/controllers/link_controller.js
275
262
  - app/jobs/mensa/application_job.rb
276
263
  - app/jobs/mensa/export_job.rb
277
264
  - app/models/concerns/.keep
@@ -296,15 +283,15 @@ files:
296
283
  - app/tables/mensa/row.rb
297
284
  - app/tables/mensa/scope.rb
298
285
  - app/tables/mensa/system_view.rb
299
- - app/views/mensa/exports/_badge.html.slim
300
- - app/views/mensa/exports/_dialog.html.slim
301
- - app/views/mensa/exports/_list.html.slim
302
- - app/views/mensa/tables/filters/show.turbo_stream.slim
303
- - app/views/mensa/tables/show.html.slim
304
- - app/views/mensa/tables/show.turbo_stream.slim
305
- - app/views/mensa/tables/views/create.turbo_stream.slim
306
- - app/views/mensa/tables/views/destroy.turbo_stream.slim
307
- - app/views/mensa/tables/views/update.turbo_stream.slim
286
+ - app/views/mensa/exports/_badge.html.erb
287
+ - app/views/mensa/exports/_dialog.html.erb
288
+ - app/views/mensa/exports/_list.html.erb
289
+ - app/views/mensa/tables/filters/show.turbo_stream.erb
290
+ - app/views/mensa/tables/show.html.erb
291
+ - app/views/mensa/tables/show.turbo_stream.erb
292
+ - app/views/mensa/tables/views/create.turbo_stream.erb
293
+ - app/views/mensa/tables/views/destroy.turbo_stream.erb
294
+ - app/views/mensa/tables/views/update.turbo_stream.erb
308
295
  - bin/importmap
309
296
  - bin/overmind
310
297
  - bin/rails
@@ -321,8 +308,10 @@ files:
321
308
  - docs/filters.png
322
309
  - docs/table.png
323
310
  - lib/generators/mensa/install_generator.rb
311
+ - lib/generators/mensa/table_generator.rb
324
312
  - lib/generators/mensa/tailwind_config_generator.rb
325
313
  - lib/generators/mensa/templates/config/initializers/mensa.rb
314
+ - lib/generators/mensa/templates/table.rb.tt
326
315
  - lib/mensa.rb
327
316
  - lib/mensa/configuration.rb
328
317
  - lib/mensa/engine.rb
@@ -344,7 +333,8 @@ post_install_message: |
344
333
  Mensa requires additional setup. Please run the following
345
334
  command to install the necessary files:
346
335
 
347
- bin/rails mensa:install:migrations
336
+ rails g mensa:install
337
+ rails mensa:install:migrations
348
338
  rdoc_options: []
349
339
  require_paths:
350
340
  - lib
@@ -1,14 +0,0 @@
1
- .mensa-table__add_filter data-controller="mensa-add-filter" data-mensa-add-filter-mensa-filter-pill-list-outlet="#mensa-filter-pill-list-#{table.table_id}" data-mensa-add-filter-operator-labels-value=operator_labels.to_json
2
- button.mensa-table__add_filter__trigger[type="button" title=t("mensa.add_filter.add", default: "Add filter") data-action="mensa-add-filter#openAllColumns"]
3
- i.fa-solid.fa-circle-plus
4
- ul.hidden.fixed.z-50.max-h-96.overflow-auto.rounded-lg.bg-white.dark:bg-gray-800.p-2.text-base.shadow-lg.ring-1.ring-black.ring-opacity-5.focus:outline-none.sm:text-sm data-mensa-add-filter-target="filterList"
5
- - table.columns.select(&:filter?).each do |column|
6
- li.text-gray-900.dark:text-gray-300.hover:bg-gray-100.dark:hover:bg-gray-700.relative.cursor-default.select-none.rounded-md.py-2.px-3.flex.items-center.gap-2 data-mensa-add-filter-target="filterListItem" data-action="click->mensa-add-filter#selectColumn mouseenter->mensa-add-filter#columnItemHovered" data-filter-column-name=column.name
7
- .label.font-normal.block.truncate.flex-1
8
- = column.human_name
9
- .check.hidden.text-primary-600.flex.items-center
10
- .fal.fa-check
11
- span.mensa-table__add_filter__enter-hint
12
- | ↵ Enter
13
-
14
- div.hidden.mensa-table__add_filter__popover_container data-mensa-add-filter-target="valuePopover" id="mensa-filter-pill-value-#{SecureRandom.base36}"
@@ -1 +0,0 @@
1
- td = cell.render(:html)
@@ -1,14 +0,0 @@
1
- .relative data-controller="mensa-column-customizer" data-mensa-column-customizer-table-name-value=table.name data-mensa-column-customizer-turbo-frame-id-value=table.table_id data-mensa-column-customizer-mensa-table-outlet="#table-#{table.table_id}"
2
- button.mensa-table__control_bar__button type="button" data-action="click->mensa-column-customizer#toggle"
3
- i class=Mensa.config.icons[:control_bar_edit]
4
- .mensa-table__column_customizer__popover.hidden data-mensa-column-customizer-target="popover"
5
- p.mensa-table__column_customizer__heading Columns
6
- ul
7
- - table.columns.reject(&:internal?).each do |column|
8
- li.mensa-table__column_customizer__row[data-mensa-column-customizer-target="columnRow" data-column-name=column.name.to_s data-visible=column.visible?.to_s draggable="true" data-action="dragstart->mensa-column-customizer#dragStart dragover->mensa-column-customizer#dragOver drop->mensa-column-customizer#drop dragend->mensa-column-customizer#dragEnd"]
9
- i.mensa-table__column_customizer__handle.fa-solid.fa-grip-vertical
10
- span.mensa-table__column_customizer__name[class=(!column.visible? ? "mensa-table__column_customizer__name--hidden" : "")]
11
- = column.human_name
12
- button.mensa-table__column_customizer__visibility type="button" data-action="click->mensa-column-customizer#toggleVisibility"
13
- i.fa-solid.fa-eye
14
- i.fa-solid.fa-eye-slash
@@ -1,43 +0,0 @@
1
- .mensa-table__control_bar data-mensa-table-target="controlBar"
2
- .flex.items-center.gap-1.py-0
3
- / Column customizer (always shown first when available)
4
- - if view_columns_ordering?
5
- = render Mensa::ColumnCustomizer::Component.new(table: table)
6
-
7
- / Save/Reset buttons — shown when there are unsaved filters or search
8
- .mensa-table__save-reset.hidden data-mensa-table-target="saveResetButtons"
9
- button.mensa-table__control_bar__button[type="button" title=t('.reset', default: 'Reset') data-action="mensa-table#cancelFiltersAndSearch"]
10
- i.fa-solid.fa-rotate-left
11
- - if table.current_user && table.supports_custom_views?
12
- .relative
13
- / Simple save — shown when the default/system view is active
14
- button.mensa-table__control_bar__button.hidden[type="button" data-mensa-table-target="saveSimple" data-action="mensa-table#saveAsNewView"]
15
- = t('.save', default: 'Save')
16
- / Save with dropdown — shown when a user-created view is active
17
- button.mensa-table__control_bar__button.hidden[type="button" data-mensa-table-target="saveSplit" data-action="mensa-table#toggleSaveDropdown"]
18
- = t('.save', default: 'Save')
19
- i.fa-solid.fa-chevron-down.text-xs
20
- ul.mensa-table__control_bar__save-dropdown.hidden data-mensa-table-target="saveDropdown"
21
- li
22
- button.mensa-table__control_bar__save-dropdown-item[type="button" data-action="mensa-table#updateCurrentViewAction"]
23
- = t('.update_view', default: 'Update view')
24
- li
25
- button.mensa-table__control_bar__save-dropdown-item[type="button" data-action="mensa-table#saveAsNewView"]
26
- = t('.save_as_new_view', default: 'Save as new view')
27
- - else
28
- button.mensa-table__control_bar__button[type="button" data-action="mensa-table#saveAsNewView"]
29
- = t('.save', default: 'Save')
30
-
31
- / Eye icon — toggles visibility of view-origin filter pills (shown by JS when needed)
32
- button.mensa-table__control_bar__button.hidden[type="button" data-mensa-table-target="eyeButton" data-action="click->mensa-table#toggleViewFilters"]
33
- i.fa-solid.fa-eye
34
-
35
- / Export
36
- - if table.exportable?
37
- button.mensa-table__control_bar__button.relative[type="button" data-action="mensa-table#export"]
38
- i data-mensa-table-target="exportIcon" class=Mensa.config.icons[:control_bar_export]
39
- = helpers.render partial: "mensa/exports/badge", locals: {table_name: table.name, user: table.current_user}
40
-
41
- - if table.exportable?
42
- = helpers.turbo_stream_from Mensa::Export.stream_name(table.name, table.current_user)
43
- = helpers.render partial: "mensa/exports/dialog", locals: {table: table}
@@ -1,7 +0,0 @@
1
- .mensa-empty-state
2
- .mensa-empty-state__icon
3
- i class=Mensa.config.icons[:search]
4
- h3.mensa-empty-state__title = t("mensa.empty_state.title", model: model_name_plural)
5
- p.mensa-empty-state__subtitle = t("mensa.empty_state.subtitle")
6
- button.mensa-empty-state__button type="button" data-action="click->mensa-table#cancelFiltersAndSearch"
7
- = t("mensa.empty_state.clear_button")
@@ -1,9 +0,0 @@
1
- .mensa-filter-pill data-controller="mensa-filter-pill" data-mensa-filter-pill-mensa-filter-pill-list-outlet="#mensa-filter-pill-list-#{filter.table.table_id}" data-mensa-filter-pill-column-name-value=filter.column.name data-mensa-filter-pill-value-value=(filter.operator_with_value? ? (filter.value.is_a?(Array) ? filter.value.to_json : filter.value) : nil ) data-mensa-filter-pill-operator-value=filter.operator data-mensa-filter-pill-operator-without-value-value=("true" unless filter.operator_with_value?) data-view-filter=("true" if view_filter?)
2
- button.mensa-filter-pill__chip[type="button" data-action="click->mensa-filter-pill#edit"]
3
- span.mensa-filter-pill__column = filter.column.human_name
4
- span.mensa-filter-pill__operator = filter.operator_label
5
- - formatted_value = filter.value.is_a?(Array) ? filter.value.join(", ") : filter.value
6
- - if formatted_value.present? && filter.operator_with_value?
7
- span.mensa-filter-pill__value = formatted_value
8
- button.mensa-filter-pill__remove[type="button" title="Remove filter" data-action="click->mensa-filter-pill#remove"]
9
- i.fa-solid.fa-xmark
@@ -1,11 +0,0 @@
1
- - has_filterable_columns = table.columns.any?(&:filter?)
2
- .mensa-table__search-bar id="mensa-filter-pill-list-#{table.table_id}" data-controller="mensa-filter-pill-list" data-mensa-table-target="filterList" data-mensa-filter-pill-list-table-name-value=table.name data-mensa-filter-pill-list-mensa-table-outlet=".mensa-table#table-#{table.table_id}" data-mensa-filter-pill-list-mensa-filter-pill-outlet=".mensa-filter-pill" data-mensa-filter-pill-list-mensa-add-filter-outlet="[data-controller=mensa-add-filter]"
3
- .mensa-table__search-bar__pills-area
4
- = render Mensa::FilterPill::Component.with_collection(table.active_filters)
5
- - if has_filterable_columns
6
- = render Mensa::AddFilter::Component.new(table: table)
7
- .mensa-table__search-bar__input-wrapper
8
- input.mensa-table__search-bar__input[type="text" name="search_query" autocomplete="off" placeholder=t(has_filterable_columns ? ".search" : ".search_only") data-mensa-filter-pill-list-target="searchInput" 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" value=params[:query]]
9
- i.mensa-table__search-bar__search-icon class=Mensa.config.icons[:search]
10
- button.mensa-table__search-bar__clear.hidden[type="button" data-mensa-filter-pill-list-target="resetSearchButton" data-action="mensa-filter-pill-list#resetSearch"]
11
- i.fas.fa-xmark
@@ -1,8 +0,0 @@
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"
4
- span = column.human_name
5
- i class=Mensa.config.icons["order_indicator#{column.sort_direction.to_s.present? ? "_#{column.sort_direction.to_s}" : ""}".to_sym]
6
- - else
7
- .container
8
- .title = column.human_name
@@ -1,6 +0,0 @@
1
- - if action.show.call(row.record)
2
- a.action href=(action.link ? table.original_view_context.instance_exec(row.record, &action.link) : '') title=action.title *action.link_attributes
3
- - if action.icon
4
- i.fa class=action.icon
5
- - else
6
- = name
@@ -1,21 +0,0 @@
1
- - if table.current_user
2
- dialog.mensa-table__save-view-dialog data-mensa-table-target="saveViewDialog" data-action="click->mensa-table#saveViewDialogBackdrop"
3
- form.mensa-table__save-view-dialog__form data-action="submit->mensa-table#confirmSaveView"
4
- header.mensa-table__save-view-dialog__header
5
- h2.mensa-table__save-view-dialog__title
6
- = t('.save_view_title', default: 'Save view')
7
- p.mensa-table__save-view-dialog__subtitle
8
- = t('.save_view_subtitle', default: 'Save the current filters, ordering and search as a reusable view.')
9
- label.mensa-table__save-view-dialog__field
10
- span.mensa-table__save-view-dialog__label
11
- = t('.view_name', default: 'Name')
12
- input.mensa-table__save-view-dialog__input type="text" required=true placeholder=t('.view_name_placeholder', default: 'e.g. Active customers') data-mensa-table-target="saveViewName"
13
- label.mensa-table__save-view-dialog__field
14
- span.mensa-table__save-view-dialog__label
15
- = t('.view_description', default: 'Description')
16
- textarea.mensa-table__save-view-dialog__textarea rows="3" placeholder=t('.view_description_placeholder', default: 'Optional notes about this view') data-mensa-table-target="saveViewDescription"
17
- .mensa-table__save-view-dialog__actions
18
- button.mensa-table__save-view-dialog__button.mensa-table__save-view-dialog__button--secondary type="button" data-action="mensa-table#cancelSaveView"
19
- = t('.cancel')
20
- button.mensa-table__save-view-dialog__button.mensa-table__save-view-dialog__button--primary type="submit"
21
- = t('.save')
@@ -1,10 +0,0 @@
1
- .mensa-table id="table-#{table.table_id}" data-mensa-table-supports-views-value="#{table.supports_views?}" data-mensa-table-table-url-value=helpers.mensa.table_url(table.name, {turbo_frame_id: table.table_id}.merge(params)) data-mensa-table-save-view-url-value=helpers.mensa.table_views_path(table.name) data-mensa-table-views-url-value=helpers.mensa.table_views_path(table.name) data-mensa-table-exports-url-value=helpers.mensa.table_exports_path(table.name) data-controller="mensa-table" data-mensa-table-mensa-filter-pill-outlet="[data-controller='mensa-filter-pill']" data-mensa-table-mensa-filter-pill-list-outlet="#mensa-filter-pill-list-#{table.table_id}" data-mensa-table-mensa-column-customizer-outlet="[data-controller='mensa-column-customizer']"
2
- .mensa-table__toolbar
3
- .mensa-table__search-container
4
- - if table.supports_views? && table.show_header?
5
- = render Mensa::Views::Component.new(table: table)
6
- div.flex.flex-1.min-w-0 id="filters-#{table.table_id}"
7
- = render Mensa::FilterPillList::Component.new(table: table)
8
- = render Mensa::ControlBar::Component.new(table: table)
9
- = render Mensa::Search::Component.new(table: table)
10
- turbo-frame id=table.table_id target="_top" data-mensa-table-target="turboFrame" data-turbo-permanent=""
@@ -1,11 +0,0 @@
1
- tr *row.link_attributes
2
- - if table. batch_actions?
3
- td.mensa-table__checkbox-col data-action="click->mensa-selection#stopPropagation"
4
- input.mensa-table__select-all type="checkbox" value=row.record.id data-action="change->mensa-selection#toggleRow" data-mensa-selection-target="rowCheckbox"
5
- - if table.actions? && Mensa.config.row_actions_position == :front
6
- td.actions
7
- = render(Mensa::RowAction::Component.with_collection(table.actions, row: row, table: table))
8
- = render(Mensa::Cell::Component.with_collection(table.display_columns, row: row))
9
- - if table.actions? && Mensa.config.row_actions_position == :back
10
- td.actions
11
- = render(Mensa::RowAction::Component.with_collection(table.actions, row: row, table: table))
@@ -1,30 +0,0 @@
1
- .overflow-y-auto.relative data-mensa-table-target="view" data-controller="mensa-selection" data-mensa-selection-batch-url-value=(table.batch_actions? ? helpers.mensa.table_batch_actions_path(table.name) : "")
2
- - if table.batch_actions?
3
- .mensa-batch-bar.hidden data-mensa-selection-target="batchBar"
4
- .mensa-batch-bar__content
5
- input.mensa-table__select-all type="checkbox" data-action="click->mensa-selection#deselectAll" data-mensa-selection-target="batchAllCheckbox"
6
- span.mensa-batch-bar__count data-mensa-selection-target="selectedCount"
7
- - table.batch_actions.each do |batch_action|
8
- button.mensa-batch-bar__button type="button" data-action="click->mensa-selection#executeBatch" data-mensa-selection-batch-action-param=batch_action.name.to_s
9
- = batch_action.title
10
- table.w-full
11
- - if table.show_header?
12
- thead
13
- tr
14
- - if table. batch_actions?
15
- th.mensa-table__checkbox-col
16
- .container
17
- input.mensa-table__select-all type="checkbox" data-action="change->mensa-selection#toggleAll" data-mensa-selection-target="headerCheckbox"
18
- - if table.actions? && Mensa.config.row_actions_position == :front
19
- th Actions
20
- = render(Mensa::Header::Component.with_collection(table.display_columns, table: table))
21
- - if table.actions? && Mensa.config.row_actions_position == :back
22
- th Actions
23
- tbody
24
- = render(Mensa::TableRow::Component.with_collection(table.rows, table: table))
25
- - if table.pagy_details&.count == 0
26
- = render Mensa::EmptyState::Component.new(table: table)
27
- - elsif table.pagy_details&.last > 1
28
- .paging
29
- span = t("mensa.paging.info", model: model_name_plural, from: table.pagy_details.from, to: table.pagy_details.to, count: table.pagy_details.count)
30
- == table.pagy_details.series_nav(anchor_string: 'data-turbo-frame="_self"')
@@ -1,52 +0,0 @@
1
- - current_view = table.all_views.find { |v| v.id == table.table_view&.id } || table.all_views.first
2
- - current_view_name = current_view&.name || t(".all", default: "All")
3
- - current_view_id = current_view&.id || ""
4
-
5
- .mensa-table__views id="mensa-views-#{table.table_id}" data-mensa-table-target="views" data-controller="mensa-views" data-mensa-views-mensa-filter-pill-list-outlet="#mensa-filter-pill-list-#{table.table_id}" data-mensa-views-table-id-value=table.table_id data-mensa-views-views-url-value=helpers.mensa.table_views_path(table.name)
6
- button.mensa-table__views__trigger type="button" data-action="mensa-views#toggleDropdown" data-mensa-views-target="trigger" aria-haspopup="listbox"
7
- span.mensa-table__views__trigger-label data-mensa-views-target="triggerLabel"
8
- = current_view_name
9
- i.fa-solid.fa-sort.mensa-table__views__trigger-icon
10
-
11
- .mensa-table__views__dropdown.hidden data-mensa-views-target="dropdown"
12
- ul role="listbox"
13
- - table.all_views.each do |view|
14
- - is_selected = view.id == table.table_view&.id || (view.id == :default && table.table_view.blank?)
15
- - is_user_view = view.id.is_a?(String) && view.id.match?(/\A[0-9a-f-]{32,}\z/i)
16
- li.mensa-table__views__option[role="option" data-view-id=view.id data-view-name=view.name data-mensa-views-target="view"]
17
- button.mensa-table__views__option-btn[type="button" data-action="mensa-views#select" data-view-id=view.id]
18
- i.mensa-table__views__option-check.fa-solid.fa-check class=("invisible" unless is_selected)
19
- span = view.name
20
- - if is_user_view
21
- button.mensa-table__views__option-menu[type="button" data-action="mensa-views#toggleSubmenu" data-view-id=view.id title="View options"]
22
- i.fa-solid.fa-ellipsis
23
- - else
24
- .mensa-table__views__option-system
25
- i.fa-solid.fa-ban
26
-
27
- / Per-view submenu (shown via JS positioning)
28
- .mensa-table__views__submenu.hidden data-mensa-views-target="submenu"
29
- button.mensa-table__views__submenu-item[type="button" data-action="mensa-views#renameView"]
30
- i.fa-solid.fa-pencil
31
- = t(".rename_view", default: "Rename view")
32
- button.mensa-table__views__submenu-item[type="button" data-action="mensa-views#duplicateView"]
33
- i.fa-solid.fa-copy
34
- = t(".duplicate_view", default: "Duplicate view")
35
- button.mensa-table__views__submenu-item.mensa-table__views__submenu-item--danger[type="button" data-action="mensa-views#deleteView"]
36
- i.fa-solid.fa-trash
37
- = t(".delete_view", default: "Delete view")
38
-
39
- / Rename dialog
40
- dialog.mensa-table__views__rename-dialog data-mensa-views-target="renameDialog" data-action="click->mensa-views#renameDialogBackdrop"
41
- form.mensa-table__views__rename-form data-action="submit->mensa-views#confirmRename"
42
- input type="hidden" data-mensa-views-target="renameViewId"
43
- h3.mensa-table__views__rename-title
44
- = t(".rename_view", default: "Rename view")
45
- label.mensa-table__views__rename-label
46
- = t(".view_name", default: "Name")
47
- input.mensa-table__views__rename-input[type="text" required=true placeholder=t(".view_name_placeholder", default: "View name") data-mensa-views-target="renameInput"]
48
- .mensa-table__views__rename-actions
49
- button.mensa-table__views__rename-btn.mensa-table__views__rename-btn--secondary[type="button" data-action="mensa-views#cancelRename"]
50
- = t(".cancel", default: "Cancel")
51
- button.mensa-table__views__rename-btn.mensa-table__views__rename-btn--primary[type="submit"]
52
- = t(".rename", default: "Rename")
@@ -1,5 +0,0 @@
1
- / Download counter shown on the export button. Hidden while there are no
2
- / completed downloads. Replaced via Turbo stream when a job finishes.
3
- - count = Mensa::Export.completed_count(table_name, user)
4
- span id=Mensa::Export.badge_dom_id(table_name, user) class="mensa-table__control_bar__badge #{'hidden' unless count.positive?}" aria-hidden=(count.positive? ? "false" : "true")
5
- = count
@@ -1,42 +0,0 @@
1
- / Export dialog rendered once per table inside the control bar. Opening it
2
- / refreshes the downloads list; submitting the form creates a new export.
3
- - user = table.current_user
4
- - exports = Mensa::Export.for_table(table.name).for_user(user).recent
5
- dialog.mensa-table__export-dialog data-mensa-table-target="exportDialog" data-action="click->mensa-table#exportDialogBackdrop"
6
- .mensa-table__export-dialog__panel
7
- header.mensa-table__export-dialog__header
8
- h2.mensa-table__export-dialog__title
9
- = t("mensa.exports.title", default: "Export %{table}", table: table.name.to_s.humanize)
10
- button.mensa-table__export-dialog__close type="button" data-action="mensa-table#cancelExport" aria-label=t("mensa.exports.close", default: "Close")
11
- i.fa-solid.fa-xmark
12
-
13
- .mensa-table__export-dialog__body
14
- = render partial: "mensa/exports/list", locals: {table_name: table.name, user: user, exports: exports}
15
-
16
- form.mensa-table__export-dialog__form data-action="submit->mensa-table#confirmExport"
17
- fieldset.mensa-table__export-dialog__fieldset
18
- legend.mensa-table__export-dialog__section-title
19
- = t("mensa.exports.new_export", default: "New export")
20
- label.mensa-table__export-dialog__option
21
- input type="radio" name="scope" value="all" checked=true
22
- span = t("mensa.exports.scope_all", default: "All records (matching current filters)")
23
- label.mensa-table__export-dialog__option
24
- input type="radio" name="scope" value="current_page"
25
- span = t("mensa.exports.scope_current_page", default: "Current page")
26
-
27
- fieldset.mensa-table__export-dialog__fieldset
28
- legend.mensa-table__export-dialog__section-title
29
- = t("mensa.exports.export_as", default: "Export as")
30
- label.mensa-table__export-dialog__option
31
- input type="radio" name="export_format" value="csv_excel" checked=true
32
- span = t("mensa.exports.format_excel", default: "CSV for Excel, Numbers, or other spreadsheet programs")
33
- label.mensa-table__export-dialog__option
34
- input type="radio" name="export_format" value="plain_csv"
35
- span = t("mensa.exports.format_plain", default: "Plain CSV file")
36
-
37
- .mensa-table__export-dialog__actions
38
- button.mensa-table__export-dialog__button.mensa-table__export-dialog__button--secondary type="button" data-action="mensa-table#cancelExport"
39
- = t("mensa.exports.cancel", default: "Cancel")
40
- button.mensa-table__export-dialog__button.mensa-table__export-dialog__button--primary type="submit"
41
- i.fa-solid.fa-file-export
42
- = t("mensa.exports.submit", default: "Export")
@@ -1,29 +0,0 @@
1
- / The list of a user's downloads for a table. Replaced via Turbo stream when a
2
- / new export is created or finishes processing.
3
- div id=Mensa::Export.list_dom_id(table_name, user) class="mensa-table__export-dialog__downloads"
4
- h3.mensa-table__export-dialog__section-title
5
- = t("mensa.exports.available_downloads", default: "Available downloads")
6
- - if exports.blank?
7
- p.mensa-table__export-dialog__empty
8
- = t("mensa.exports.empty", default: "You have no downloads yet. Create one below.")
9
- - else
10
- ul.mensa-table__export-dialog__list
11
- - exports.each do |export|
12
- li.mensa-table__export-dialog__item
13
- .mensa-table__export-dialog__item-info
14
- span.mensa-table__export-dialog__item-name
15
- = export.filename.presence || t("mensa.exports.item_name", default: "%{table} export", table: export.table_name.to_s.humanize)
16
- span.mensa-table__export-dialog__item-meta
17
- = export.created_at.strftime("%Y-%m-%d %H:%M")
18
- .mensa-table__export-dialog__item-action
19
- - if export.downloadable?
20
- = link_to mensa.download_table_export_path(export.table_name, export), class: "mensa-table__export-dialog__download", data: {turbo: false} do
21
- i.fa-solid.fa-download
22
- = t("mensa.exports.download", default: "Download")
23
- - elsif export.failed?
24
- span.mensa-table__export-dialog__status.mensa-table__export-dialog__status--failed
25
- = t("mensa.exports.failed", default: "Failed")
26
- - else
27
- span.mensa-table__export-dialog__status.mensa-table__export-dialog__status--pending
28
- i.fa-solid.fa-spinner.fa-spin
29
- = t("mensa.exports.processing", default: "Preparing…")
@@ -1,36 +0,0 @@
1
- = turbo_stream.update params[:target] do
2
- .mensa-table__add_filter__popover_container__heading
3
- = @column.human_name
4
- - if @column.filter.operator_with_value?
5
- - collection = @column.filter.collection
6
- - if collection.present?
7
- - unless @multiple
8
- input[type="hidden" data-mensa-add-filter-target="value" value=@values.first]
9
- ul.mensa-table__add_filter__popover_container__values data-multiple=("true" if @multiple)
10
- - collection.each do |item|
11
- - opt_label = item.is_a?(Array) ? item.first.to_s : item.to_s
12
- - opt_value = item.is_a?(Array) ? item.last.to_s : item.to_s
13
- - is_selected = @values.include?(opt_value)
14
- li.mensa-table__add_filter__popover_container__value[data-mensa-add-filter-target="valueOption" data-value=opt_value data-label=opt_label data-selected=("true" if is_selected) data-action="click->mensa-add-filter#selectValue mouseenter->mensa-add-filter#highlightItem"]
15
- - if @multiple
16
- span.mensa-table__add_filter__checkbox class=("mensa-table__add_filter__checkbox--checked" if is_selected)
17
- - else
18
- i.mensa-table__add_filter__popover_container__value__check.fa-solid.fa-check class=("invisible" unless is_selected)
19
- span.flex-1
20
- = opt_label
21
- span.mensa-table__add_filter__enter-hint
22
- | ↵ Enter
23
- - else
24
- input.mensa-table__add_filter__popover_container__input[type=@column.filter.input_type value=@values.first autocomplete="off" inputmode=(@column.type == :integer ? "numeric" : nil) step=(@column.type == :integer ? 1 : (@column.type == :datetime ? 1 : nil)) data-mensa-add-filter-target="value" data-action="input->mensa-add-filter#manualValueChanged keydown.enter->mensa-add-filter#applyManualValue"]
25
- hr.mensa-table__add_filter__popover_container__separator
26
- ul.mensa-table__add_filter__popover_container__operators
27
- - @column.filter.operators.each do |operator_name, label, requires_value|
28
- li.mensa-table__add_filter__popover_container__operator[data-mensa-add-filter-target="operatorOption" data-operator=operator_name data-requires-value=(requires_value ? "true" : "false") data-selected=("true" if @operator == operator_name.to_s) data-action="click->mensa-add-filter#selectOperator mouseenter->mensa-add-filter#highlightItem"]
29
- i.mensa-table__add_filter__popover_container__operator__check.fa-solid.fa-check class=("invisible" unless @operator == operator_name.to_s)
30
- span.flex-1
31
- = label
32
- span.mensa-table__add_filter__enter-hint
33
- | ↵ Enter
34
- hr.mensa-table__add_filter__popover_container__separator
35
- a.mensa-table__add_filter__popover_container__clear[href="#" data-action="click->mensa-add-filter#reset"]
36
- | Clear
@@ -1,4 +0,0 @@
1
- | Test
2
- button.text-xs Esc
3
- turbo-frame id=@table.table_id target="_top"
4
- = render Mensa::View::Component.new(@table)
@@ -1,5 +0,0 @@
1
- = turbo_stream.update "filters-#{@table.table_id}" do
2
- = render Mensa::FilterPillList::Component.new(table: @table)
3
-
4
- = turbo_stream.update @table.table_id do
5
- = render Mensa::View::Component.new(@table)
@@ -1,11 +0,0 @@
1
- / Replace the views tabs so the newly saved view tab appears, selected.
2
- = turbo_stream.replace "mensa-views-#{@table.table_id}" do
3
- = render Mensa::Views::Component.new(table: @table)
4
-
5
- / Clear the filter pills — the saved view starts fresh with no extra filters.
6
- = turbo_stream.update "filters-#{@table.table_id}" do
7
- = render Mensa::FilterPillList::Component.new(table: @table)
8
-
9
- / Re-render the table body with the saved view's data.
10
- = turbo_stream.update @table.table_id do
11
- = render Mensa::View::Component.new(@table)