mensa 0.2.4 → 0.2.6

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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +6 -2
  3. data/.devcontainer/compose.yaml +1 -1
  4. data/.devcontainer/devcontainer.json +31 -29
  5. data/.devcontainer/postCreate.sh +8 -0
  6. data/.devcontainer/postStart.sh +9 -0
  7. data/.gitignore +3 -1
  8. data/.zed/tasks.json +12 -0
  9. data/CHANGELOG.md +6 -0
  10. data/Gemfile.lock +155 -153
  11. data/Procfile +1 -1
  12. data/README.md +95 -60
  13. data/app/assets/stylesheets/mensa/application.css +14 -11
  14. data/app/components/mensa/add_filter/component.css +110 -5
  15. data/app/components/mensa/add_filter/component.html.slim +10 -12
  16. data/app/components/mensa/add_filter/component.rb +8 -2
  17. data/app/components/mensa/add_filter/component_controller.js +697 -85
  18. data/app/components/mensa/cell/component.css +9 -0
  19. data/app/components/mensa/column_customizer/component.css +40 -0
  20. data/app/components/mensa/column_customizer/component.html.slim +14 -0
  21. data/app/components/mensa/column_customizer/component.rb +13 -0
  22. data/app/components/mensa/column_customizer/component_controller.js +383 -0
  23. data/app/components/mensa/control_bar/component.css +127 -4
  24. data/app/components/mensa/control_bar/component.html.slim +41 -14
  25. data/app/components/mensa/control_bar/component.rb +2 -6
  26. data/app/components/mensa/empty_state/component.css +20 -0
  27. data/app/components/mensa/empty_state/component.html.slim +7 -0
  28. data/app/components/mensa/empty_state/component.rb +18 -0
  29. data/app/components/mensa/filter_pill/component.css +23 -0
  30. data/app/components/mensa/filter_pill/component.html.slim +9 -0
  31. data/app/components/mensa/filter_pill/component.rb +24 -0
  32. data/app/components/mensa/filter_pill/component_controller.js +52 -0
  33. data/app/components/mensa/filter_pill_list/component.css +63 -0
  34. data/app/components/mensa/filter_pill_list/component.html.slim +11 -0
  35. data/app/components/mensa/{filter_list → filter_pill_list}/component.rb +1 -1
  36. data/app/components/mensa/filter_pill_list/component_controller.js +749 -0
  37. data/app/components/mensa/header/component.css +41 -43
  38. data/app/components/mensa/header/component.html.slim +7 -7
  39. data/app/components/mensa/header/component.rb +1 -1
  40. data/app/components/mensa/row_action/component.html.slim +2 -2
  41. data/app/components/mensa/row_action/component.rb +1 -1
  42. data/app/components/mensa/search/component.css +68 -9
  43. data/app/components/mensa/search/component.html.slim +19 -15
  44. data/app/components/mensa/search/component.rb +1 -1
  45. data/app/components/mensa/search/component_controller.js +39 -49
  46. data/app/components/mensa/selection/component_controller.js +147 -0
  47. data/app/components/mensa/table/component.css +28 -0
  48. data/app/components/mensa/table/component.html.slim +9 -6
  49. data/app/components/mensa/table/component.rb +1 -0
  50. data/app/components/mensa/table/component_controller.js +524 -76
  51. data/app/components/mensa/table_row/component.css +6 -0
  52. data/app/components/mensa/table_row/component.html.slim +8 -3
  53. data/app/components/mensa/table_row/component.rb +1 -1
  54. data/app/components/mensa/view/component.css +97 -29
  55. data/app/components/mensa/view/component.html.slim +23 -10
  56. data/app/components/mensa/view/component.rb +5 -0
  57. data/app/components/mensa/views/component.css +106 -13
  58. data/app/components/mensa/views/component.html.slim +51 -17
  59. data/app/components/mensa/views/component_controller.js +245 -20
  60. data/app/controllers/mensa/application_controller.rb +1 -1
  61. data/app/controllers/mensa/tables/batch_actions_controller.rb +24 -0
  62. data/app/controllers/mensa/tables/exports_controller.rb +96 -0
  63. data/app/controllers/mensa/tables/filters_controller.rb +6 -2
  64. data/app/controllers/mensa/tables/views_controller.rb +108 -0
  65. data/app/controllers/mensa/tables_controller.rb +5 -14
  66. data/app/helpers/mensa/application_helper.rb +4 -1
  67. data/app/javascript/mensa/application.js +2 -2
  68. data/app/javascript/mensa/controllers/application_controller.js +5 -21
  69. data/app/javascript/mensa/controllers/index.js +16 -7
  70. data/app/jobs/mensa/export_job.rb +77 -85
  71. data/app/models/mensa/export.rb +93 -0
  72. data/app/tables/mensa/action.rb +3 -1
  73. data/app/tables/mensa/base.rb +103 -17
  74. data/app/tables/mensa/batch_action.rb +27 -0
  75. data/app/tables/mensa/cell.rb +21 -6
  76. data/app/tables/mensa/column.rb +30 -25
  77. data/app/tables/mensa/config/action_dsl.rb +1 -1
  78. data/app/tables/mensa/config/batch_dsl.rb +13 -0
  79. data/app/tables/mensa/config/column_dsl.rb +1 -0
  80. data/app/tables/mensa/config/dsl_logic.rb +8 -4
  81. data/app/tables/mensa/config/filter_dsl.rb +4 -1
  82. data/app/tables/mensa/config/render_dsl.rb +1 -1
  83. data/app/tables/mensa/config/table_dsl.rb +14 -4
  84. data/app/tables/mensa/config/view_dsl.rb +2 -0
  85. data/app/tables/mensa/config_readers.rb +34 -3
  86. data/app/tables/mensa/filter.rb +94 -14
  87. data/app/tables/mensa/row.rb +1 -1
  88. data/app/tables/mensa/scope.rb +25 -13
  89. data/app/views/mensa/exports/_badge.html.slim +5 -0
  90. data/app/views/mensa/exports/_dialog.html.slim +42 -0
  91. data/app/views/mensa/exports/_list.html.slim +29 -0
  92. data/app/views/mensa/tables/filters/show.turbo_stream.slim +34 -6
  93. data/app/views/mensa/tables/show.html.slim +2 -0
  94. data/app/views/mensa/tables/show.turbo_stream.slim +1 -1
  95. data/app/views/mensa/tables/views/create.turbo_stream.slim +11 -0
  96. data/app/views/mensa/tables/views/destroy.turbo_stream.slim +11 -0
  97. data/app/views/mensa/tables/views/update.turbo_stream.slim +11 -0
  98. data/bin/setup +1 -1
  99. data/config/locales/en.yml +45 -1
  100. data/config/locales/nl.yml +46 -1
  101. data/config/routes.rb +7 -0
  102. data/db/migrate/20260604120000_create_mensa_exports.rb +25 -0
  103. data/docs/columns.png +0 -0
  104. data/docs/export.png +0 -0
  105. data/docs/filters.png +0 -0
  106. data/docs/table.png +0 -0
  107. data/lib/generators/mensa/tailwind_config_generator.rb +3 -3
  108. data/lib/generators/mensa/templates/config/initializers/mensa.rb +1 -1
  109. data/lib/mensa/configuration.rb +35 -15
  110. data/lib/mensa/engine.rb +15 -10
  111. data/lib/mensa/version.rb +1 -1
  112. data/lib/mensa.rb +2 -2
  113. data/lib/tasks/mensa_tasks.rake +1 -1
  114. data/mensa.gemspec +3 -2
  115. data/mise.toml +8 -0
  116. data/package-lock.json +0 -7
  117. metadata +60 -15
  118. data/app/components/mensa/filter/component_controller.js +0 -12
  119. data/app/components/mensa/filter_list/component.css +0 -14
  120. data/app/components/mensa/filter_list/component.html.slim +0 -14
  121. data/app/components/mensa/filter_list/component_controller.js +0 -14
  122. /data/{rubocop.yml → .rubocop.yml} +0 -0
data/README.md CHANGED
@@ -4,6 +4,8 @@ Fast and awesome tables, with pagination, sorting, filtering and custom views.
4
4
 
5
5
  ![table](./docs/table.png)
6
6
  ![filters](./docs/filters.png)
7
+ ![columns](./docs/columns.png)
8
+ ![export](./docs/export.png)
7
9
 
8
10
  Features:
9
11
 
@@ -13,84 +15,105 @@ Features:
13
15
  - [x] tables without headers (and without most of the above)
14
16
  - [x] filtering of multiple columns
15
17
  - [X] Hide filter icon in case there are no filters
18
+ - [X] column ordering
19
+ - [X] editing of existing filters
20
+ - [X] view selection and exports per view
21
+ - [X] multiple selection of rows and batch processing
16
22
 
17
- Still to do:
18
- - [ ] column sorting
19
- - [ ] editing of existing filters
20
- - [ ] view selection and exports per view
21
- - [ ] multiple selection of rows
23
+ Todo/Fixme:
24
+ - [ ] exports can be mailed - daily/weekly/monthly/quarterly/bi-yearly/yearly (time configurable)
25
+ - [ ] Search only works on table text columns
22
26
 
23
- Optionally:
27
+ Nice to haves:
24
28
 
25
29
  - [ ] group by
26
30
  - [ ] sum/max/min
27
31
  - [ ] tables backed by arrays (of ActiveModel)
28
32
 
29
- Todo/Fixme:
30
-
31
- - [ ] Search only works on table text columns
32
-
33
33
  ## Usage
34
34
 
35
35
  Add tables in your app/tables folder, inheriting from ApplicationTable.
36
36
  This in turn should inherit from Mensa::Base.
37
37
 
38
+ You can give columns an arbitrary name, it can match the database column, translations will be taken from `activerecord.attributes.<model>.<column>`:
39
+
40
+ ```yaml
41
+ en:
42
+ activerecord:
43
+ attributes:
44
+ user:
45
+ name: Full name
46
+ ```
47
+
38
48
  ```ruby
39
49
  class UserTable < ApplicationTable
40
- definition do
41
- model User # implicit from name
42
-
43
- order name: :desc
44
-
45
- column(:name) do
46
- attribute :name # Optional, we can deduct this from the column name
47
- sortable true
48
- sanitize true
49
- internal false
50
- visible true
51
- filter do
52
- collection -> { }
53
- scope -> { where(name: ...) }
54
- end
50
+ model User # implicit from name
51
+
52
+ order name: :desc
53
+
54
+ 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: ...) }
55
63
  end
64
+ operators [:is, :isnt] # Optional, mensa tries to deduce this from the column information
65
+ end
56
66
 
57
- column(:nr_of_roles) do
58
- attribute "roles_count" # We use a database column here
59
- end
67
+ column(:nr_of_roles) do
68
+ attribute "roles_count" # We use a database column here
69
+ end
60
70
 
61
- # You can add one or more actions to a row
62
- action :delete do
63
- title "Delete row"
64
- link { |user| user_path(user) }
65
- icon "fa-regular fa-trash"
66
- link_attributes data: {"turbo-confirm": "Are you sure you want to delete the user?", "turbo-method": :delete}
67
- show ->(user) { true }
68
- end
71
+ # You can add one or more actions to a row
72
+ action :delete do
73
+ title "Delete row"
74
+ link { |user| user_path(user) }
75
+ icon "fa-regular fa-trash"
76
+ link_attributes data: {"turbo-confirm": "Are you sure you want to delete the user?", "turbo-method": :delete}
77
+ show ->(user) { true }
78
+ end
69
79
 
70
- link { |user| edit_user_path(user) }
71
- supports_views true # This table supports custom views
72
- show_header true
73
- view_columns_sorting false # Disabled for now
74
- view_condensed false # Default false
75
- view_condensed_toggle true # Whether to show the toggle, default true
76
-
77
- # Add system views
78
- view :concept do
79
- name "Concept"
80
- filter :state do
81
- operator :equals
82
- value "concept"
83
- end
80
+ link { |user| edit_user_path(user) }
81
+ supports_views true # This table supports custom views
82
+ show_header true
83
+ view_columns_ordering false # Disabled for now
84
+
85
+ # Add system views
86
+ # Mensa will always create a systemview (:default) with name 'All' showing all records.
87
+ # If you want to rename it, for example because you don't show all records in your default scope, add it and give it a name like below.
88
+ view :default do
89
+ name "Default"
90
+ description "Some descriptive text"
91
+ end
92
+ view :concept do
93
+ name "Concept"
94
+ filter :state do
95
+ operator :is
96
+ value "concept"
97
+ end
98
+ end
99
+
100
+ batch :confirm do
101
+ description "Confirm users"
102
+ process do |records|
103
+ ConfirmUsersJob.perform_later(records.to_a)
84
104
  end
85
105
  end
106
+
107
+ scope do
108
+ User.all
109
+ end
86
110
  end
87
111
  ```
88
112
 
89
- Currently mensa depends on satis, but that is something we might remove in a future version.
90
113
  You can show your tables on the page using the following:
91
114
 
92
115
  ```slim
93
- = sts.table :users
116
+ = table :users
94
117
  ```
95
118
 
96
119
  #### Custom views
@@ -99,17 +122,16 @@ Custom views are views not defined by the developer (SystemViews) but by the end
99
122
 
100
123
  Initial support for custom-views is there, but pretty rudimentary:
101
124
 
102
- `Mensa::TableView.create(table: "users", name: "Guests", data: {filters: {role: {value: "guest"}}})`
125
+ `Mensa::TableView.create(table: "users", name: "Guests", config: {filters: {role: {value: "guest"}}})`
103
126
 
104
127
  ### Fast
105
128
 
106
- Mensa selects only the data it needs, based on the columns. Sometimes it needs additional columns to do it's work, but you don't want them displayed.
107
- This can be done by adding `internal true` to the column definition, or shorter: use `internal` instead
129
+ Mensa selects only the data it needs, based on the columns. Sometimes it needs additional columns to do it's work, but you don't want them displayed. This can be done by adding `internal true` to the column definition, or shorter: use `internal` instead. If your table scope joins an association, Mensa also auto-adds the foreign key column as internal when it is needed.
108
130
 
109
131
  ```ruby
110
- internal :born_on
132
+ internal :born_on
111
133
  column :age do
112
- attribute "EXTRACT(YEAR FROM AGE(born_on))::int"
134
+ attribute "EXTRACT(YEAR FROM AGE(born_on))::int" # here born_on is used internally, so we ned to select is
113
135
  end
114
136
  ```
115
137
 
@@ -124,26 +146,33 @@ end
124
146
  export BUNDLE_RUBYGEMS__PKG__GITHUB__COM=ghp_xxxxxxw
125
147
  export RBENV_VERSION=$(cat .ruby-version)
126
148
  ```
149
+
127
150
  - Run `direnv allow`
151
+
152
+ If you use devcontainers:
128
153
  - Open with Visual Studio Code (or with any other editor) and reopen in container.
129
154
  - Run `bin/overmind s`
130
155
 
156
+ If you're not using devcontainers:
157
+ - Run `bin/overmind s`
158
+
131
159
  ### Docs
132
160
 
133
161
  Using the following in your view will render Mensa::Table::Component
134
162
  ```slim
135
- = sts.table :users
163
+ = table :users
136
164
  ```
137
165
 
138
166
  The Mensa::Table::Component will render:
139
167
  - Mensa::Search::Component
140
- - Mensa::FilterList::Component
168
+ - Mensa::FilterPillList::Component
169
+ - Mensa::FilterPill::Component
170
+ - Mensa::AddFilter::Component
141
171
  - Mensa::Views::Component
142
172
  - renders a views list
143
173
  - Mensa::ControlBar::Component
144
174
  - search icon
145
175
  - filter icon
146
- - condensed toggle
147
176
  - export icon
148
177
  - turbo-frame with the actual table you see (which is rendered by Mensa::View::Component)
149
178
 
@@ -173,6 +202,12 @@ Always use `bundle` to install the gem. Next use the install generator to instal
173
202
  $ bin/rails g mensa:install
174
203
  ```
175
204
 
205
+ ### Exports
206
+
207
+ Exporting is built into the table's control bar. Clicking the export button opens
208
+ a dialog that lists the user's previous downloads and lets them request a new
209
+ export (scope and CSV format).
210
+
176
211
  ## Contributing
177
212
 
178
213
  ```
@@ -1,11 +1,14 @@
1
- @import '../../../components/mensa/add_filter/component.css';
2
- @import '../../../components/mensa/cell/component.css';
3
- @import '../../../components/mensa/control_bar/component.css';
4
- @import '../../../components/mensa/filter_list/component.css';
5
- @import '../../../components/mensa/header/component.css';
6
- @import '../../../components/mensa/row_action/component.css';
7
- @import '../../../components/mensa/search/component.css';
8
- @import '../../../components/mensa/table/component.css';
9
- @import '../../../components/mensa/table_row/component.css';
10
- @import '../../../components/mensa/view/component.css';
11
- @import '../../../components/mensa/views/component.css';
1
+ @import "../../../components/mensa/add_filter/component.css";
2
+ @import "../../../components/mensa/column_customizer/component.css";
3
+ @import "../../../components/mensa/cell/component.css";
4
+ @import "../../../components/mensa/control_bar/component.css";
5
+ @import "../../../components/mensa/empty_state/component.css";
6
+ @import "../../../components/mensa/filter_pill/component.css";
7
+ @import "../../../components/mensa/filter_pill_list/component.css";
8
+ @import "../../../components/mensa/header/component.css";
9
+ @import "../../../components/mensa/row_action/component.css";
10
+ @import "../../../components/mensa/search/component.css";
11
+ @import "../../../components/mensa/table/component.css";
12
+ @import "../../../components/mensa/table_row/component.css";
13
+ @import "../../../components/mensa/view/component.css";
14
+ @import "../../../components/mensa/views/component.css";
@@ -1,13 +1,118 @@
1
- .sts-table {
1
+ .mensa-table {
2
2
  &__add_filter {
3
- @apply relative;
3
+ @apply relative inline-flex items-center;
4
+
5
+ &__trigger {
6
+ /* Hidden by default; shown via sibling selector when filter pills exist */
7
+ @apply hidden items-center justify-center w-5 h-5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 cursor-pointer transition-colors text-sm;
8
+ }
9
+
10
+ &__enter-hint {
11
+ display: none;
12
+ @apply text-xs text-gray-400 bg-gray-100 dark:bg-gray-700 rounded px-1.5 py-0.5 whitespace-nowrap;
13
+ }
14
+
15
+ &__checkbox {
16
+ @apply h-4 w-4 flex-none rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 inline-block;
17
+
18
+ &--checked {
19
+ @apply bg-gray-900 border-gray-900 dark:bg-white dark:border-white;
20
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='white'%3E%3Cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3E%3C/svg%3E");
21
+ background-size: 100% 100%;
22
+ background-repeat: no-repeat;
23
+ background-position: center;
24
+ }
25
+ }
4
26
 
5
27
  &__popover_container {
6
- @apply p-2 absolute z-10 mt-1 max-h-60 w-64 overflow-auto rounded-md bg-white dark:bg-gray-800 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm;
28
+ @apply p-4 fixed z-50 w-72 rounded-lg bg-white dark:bg-gray-800 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm;
29
+
30
+ &__heading {
31
+ @apply font-semibold text-gray-900 dark:text-gray-100 mb-2;
32
+ }
33
+
34
+ input&__input {
35
+ @apply w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 shadow-sm placeholder:text-gray-400 focus:border-primary-500 focus:ring-2 focus:ring-primary-500 focus:outline-none;
36
+ }
37
+
38
+ &__separator {
39
+ @apply border-t border-gray-200 dark:border-gray-600 my-3 -mx-4;
40
+ }
41
+
42
+ &__values {
43
+ @apply mb-2 max-h-[20rem] overflow-y-scroll;
44
+ }
45
+
46
+ &__value {
47
+ @apply flex items-center gap-2 py-1.5 px-2 rounded-md cursor-pointer text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 select-none;
48
+
49
+ &__check {
50
+ @apply w-4 flex-none inline-flex items-center justify-center text-xs;
51
+ }
52
+ }
53
+
54
+ &__operators {
55
+ @apply mb-2;
56
+ }
57
+
58
+ &__operator {
59
+ @apply flex items-center gap-2 py-1.5 rounded-md cursor-pointer text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 select-none;
60
+
61
+ &__check {
62
+ @apply w-4 flex-none inline-flex items-center justify-center text-xs;
63
+ }
64
+ }
7
65
 
8
66
  &__clear {
9
- @apply text-gray-600 dark:text-gray-400 no-underline;
67
+ @apply block mt-3 text-gray-500 dark:text-gray-400 no-underline hover:text-gray-700 dark:hover:text-gray-200 cursor-pointer;
10
68
  }
11
69
  }
12
70
  }
13
- }
71
+ }
72
+
73
+ /* Show enter hint on hover or keyboard highlight — covers column list and value popover */
74
+ .mensa-table__add_filter li:hover .mensa-table__add_filter__enter-hint,
75
+ .mensa-table__add_filter li.highlighted .mensa-table__add_filter__enter-hint {
76
+ display: inline-flex;
77
+ }
78
+
79
+ /* Keyboard highlight background — mirrors the hover style */
80
+ .mensa-table__add_filter li.highlighted {
81
+ @apply bg-gray-100 dark:bg-gray-700;
82
+ }
83
+
84
+ /* Show + when user-added (non-view-filter) committed pills are present.
85
+ User pills are always visible, so no ancestor visibility check needed. */
86
+ .mensa-table__search-bar__pills-area:has(
87
+ .mensa-filter-pill:not([data-view-filter="true"]):not(
88
+ .mensa-filter-pill--pending
89
+ )
90
+ ):not(:has(.mensa-filter-pill--pending))
91
+ .mensa-table__add_filter
92
+ .mensa-table__add_filter__trigger {
93
+ @apply inline-flex;
94
+ }
95
+
96
+ /* Show + when view-defined filter pills are present AND currently visible
97
+ (eye toggle on). Hidden view filters must not reveal the + button. */
98
+ .mensa-table:not(.mensa-table--view-filters-hidden)
99
+ .mensa-table__search-bar__pills-area:has(
100
+ .mensa-filter-pill[data-view-filter="true"]
101
+ ):not(:has(.mensa-filter-pill--pending))
102
+ .mensa-table__add_filter
103
+ .mensa-table__add_filter__trigger {
104
+ @apply inline-flex;
105
+ }
106
+
107
+ /* While a filter is being configured, collapse the add-filter wrapper so it
108
+ doesn't create an extra flex gap between the pending pill and the search input.
109
+ The value popover inside is position:fixed so display:contents doesn't affect it. */
110
+ .mensa-table__search-bar__pills-area:has(.mensa-filter-pill--pending)
111
+ .mensa-table__add_filter {
112
+ display: contents;
113
+ }
114
+
115
+ /* Pending pill while the value popover is open — rounded on both sides (no remove button) */
116
+ .mensa-filter-pill--pending .mensa-filter-pill__chip {
117
+ @apply rounded-md opacity-70;
118
+ }
@@ -1,16 +1,14 @@
1
- .sts-table__add_filter data-controller="mensa-add-filter" data-mensa-add-filter-mensa-table-outlet=".mensa-table#table-#{table.table_id}"
2
- button.relative.w-full.cursor-default.rounded-md.bg-white.dark:bg-gray-800.py-1.5.pl-3.pr-6.text-left.text-gray-400.dark:text-gray-400.shadow-sm.border.border-dashed.focus:outline-none.focus:ring-2.focus:ring-primary-600.sm:text-sm.sm:leading-6 type="button" data-action="mensa-add-filter#toggle"
3
- span.mr-2.block.truncate data-mensa-add-filter-target="description"
4
- = t('.add_filter')
5
- span.pointer-events-none.absolute.inset-y-0.right-0.flex.items-center.pr-2
6
- div class=Mensa.config.icons[:filters_add_filter]
7
-
8
- ul.hidden.absolute.z-10.mt-1.max-h-60.w-64.overflow-auto.rounded-md.bg-white.dark:bg-gray-800.py-1.text-base.shadow-lg.ring-1.ring-black.ring-opacity-5.focus:outline-none.sm:text-sm data-mensa-add-filter-target="filterList"
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"
9
5
  - table.columns.select(&:filter?).each do |column|
10
- li#listbox-option-0.text-gray-900.dark:text-gray-400.hover:bg-gray-100.relative.cursor-default.select-none.py-2.pl-8.pr-4 data-mensa-add-filter-target="filterListItem" data-action="click->mensa-add-filter#selectColumn" data-filter-column-name=column.name
11
- .label.font-normal.block.truncate
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
12
8
  = column.human_name
13
- .check.hidden.text-primary-600.absolute.inset-y-0.left-0.flex.items-center.pl-3
9
+ .check.hidden.text-primary-600.flex.items-center
14
10
  .fal.fa-check
11
+ span.mensa-table__add_filter__enter-hint
12
+ | ↵ Enter
15
13
 
16
- div.hidden.sts-table__add_filter__popover_container data-mensa-add-filter-target="valuePopover" id="mensa-filter-value-#{SecureRandom.base36}"
14
+ div.hidden.mensa-table__add_filter__popover_container data-mensa-add-filter-target="valuePopover" id="mensa-filter-pill-value-#{SecureRandom.base36}"
@@ -2,12 +2,18 @@
2
2
 
3
3
  module Mensa
4
4
  module AddFilter
5
- class Component < ::Mensa::ApplicationComponent
5
+ class Component < Mensa::ApplicationComponent
6
6
  attr_reader :table
7
7
 
8
8
  def initialize(table:)
9
9
  @table = table
10
10
  end
11
+
12
+ def operator_labels
13
+ Mensa::Filter.OPERATORS.to_h do |name, label, _requires_value|
14
+ [name, label]
15
+ end
16
+ end
11
17
  end
12
18
  end
13
- end
19
+ end