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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +5 -21
- data/README.md +25 -42
- data/app/components/mensa/add_filter/component.html.erb +31 -0
- data/app/components/mensa/cell/component.html.erb +1 -0
- data/app/components/mensa/column_customizer/component.html.erb +31 -0
- data/app/components/mensa/control_bar/component.html.erb +56 -0
- data/app/components/mensa/empty_state/component.html.erb +10 -0
- data/app/components/mensa/filter_pill/component.html.erb +20 -0
- data/app/components/mensa/filter_pill_list/component.html.erb +30 -0
- data/app/components/mensa/header/component.html.erb +12 -0
- data/app/components/mensa/row_action/component.html.erb +10 -0
- data/app/components/mensa/search/component.html.erb +26 -0
- data/app/components/mensa/table/component.html.erb +25 -0
- data/app/components/mensa/table_row/component.html.erb +18 -0
- data/app/components/mensa/view/component.html.erb +51 -0
- data/app/components/mensa/views/component.html.erb +74 -0
- data/app/tables/mensa/action.rb +8 -1
- data/app/views/mensa/exports/_badge.html.erb +6 -0
- data/app/views/mensa/exports/_dialog.html.erb +52 -0
- data/app/views/mensa/exports/_list.html.erb +32 -0
- data/app/views/mensa/tables/filters/show.turbo_stream.erb +58 -0
- data/app/views/mensa/tables/show.html.erb +5 -0
- data/app/views/mensa/tables/show.turbo_stream.erb +7 -0
- data/app/views/mensa/tables/views/create.turbo_stream.erb +11 -0
- data/app/views/mensa/tables/views/destroy.turbo_stream.erb +11 -0
- data/app/views/mensa/tables/views/update.turbo_stream.erb +11 -0
- data/lib/generators/mensa/table_generator.rb +15 -0
- data/lib/generators/mensa/templates/config/initializers/mensa.rb +4 -5
- data/lib/generators/mensa/templates/table.rb.tt +18 -0
- data/lib/mensa/engine.rb +0 -1
- data/lib/mensa/version.rb +1 -1
- data/mensa.gemspec +2 -4
- metadata +29 -54
- data/app/components/mensa/add_filter/component.html.slim +0 -14
- data/app/components/mensa/cell/component.html.slim +0 -1
- data/app/components/mensa/column_customizer/component.html.slim +0 -14
- data/app/components/mensa/control_bar/component.html.slim +0 -43
- data/app/components/mensa/empty_state/component.html.slim +0 -7
- data/app/components/mensa/filter_pill/component.html.slim +0 -9
- data/app/components/mensa/filter_pill_list/component.html.slim +0 -11
- data/app/components/mensa/header/component.html.slim +0 -8
- data/app/components/mensa/row_action/component.html.slim +0 -6
- data/app/components/mensa/search/component.html.slim +0 -21
- data/app/components/mensa/table/component.html.slim +0 -10
- data/app/components/mensa/table_row/component.html.slim +0 -11
- data/app/components/mensa/view/component.html.slim +0 -30
- data/app/components/mensa/views/component.html.slim +0 -52
- data/app/views/mensa/exports/_badge.html.slim +0 -5
- data/app/views/mensa/exports/_dialog.html.slim +0 -42
- data/app/views/mensa/exports/_list.html.slim +0 -29
- data/app/views/mensa/tables/filters/show.turbo_stream.slim +0 -36
- data/app/views/mensa/tables/show.html.slim +0 -4
- data/app/views/mensa/tables/show.turbo_stream.slim +0 -5
- data/app/views/mensa/tables/views/create.turbo_stream.slim +0 -11
- data/app/views/mensa/tables/views/destroy.turbo_stream.slim +0 -11
- 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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 194b34ee31bebddc3962cc66e5c789e5369f828eb6087f67f72b54aba97f65d8
|
|
4
|
+
data.tar.gz: 1ead92c4d986f5e69c3d5745fcee27541f8205bf0106bd25f757b7603cdc117f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f5c078859d1c6214b8b65ab36fd077a2c36e2f5b50a69efd0dc20621d6373977be10ed543bc68add8b81338b4322903c3c305a15a0bd47c8ea906d77953c2a9d
|
|
7
|
+
data.tar.gz: 6e68ccdd3ffea1ef460876f61a9d624a8d7de198addad7c712bfac67eac1cc08fbe0874221ba76f241ce5d47c8dec0b09c7950f058865ee232ca540868bea95d
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
mensa (0.3.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|

|
|
6
7
|

|
|
@@ -52,16 +53,7 @@ class UserTable < ApplicationTable
|
|
|
52
53
|
order name: :desc
|
|
53
54
|
|
|
54
55
|
column(:name) do
|
|
55
|
-
|
|
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
|
-
```
|
|
116
|
-
|
|
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
|
|
134
|
+
- Setup your direnv, add the following to your `mise.toml`:
|
|
144
135
|
|
|
145
136
|
```
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
```
|
|
163
|
-
|
|
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
|
-
$
|
|
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>
|