mensa 0.6.14 → 0.6.16
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/.shipkit.yml +1 -1
- data/CHANGELOG.md +20 -0
- data/Gemfile.lock +1 -1
- data/README.md +53 -0
- data/app/controllers/mensa/tables/exports_controller.rb +8 -0
- data/app/tables/mensa/base.rb +5 -2
- data/app/tables/mensa/filter.rb +14 -3
- data/lib/mensa/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0a88070a879c44aa30934fd328a74c21546c2517999731ad033dc10022d2a4ee
|
|
4
|
+
data.tar.gz: 3940bc3931ce9f0a0aad748c378cbd7c3231616cedea960f7c24ab7bdc974cf2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 77fe83cd050e611f24086db47cd0a0f9330459289390df37361a97f82950819a0b22a0d6573a094be0cf4d7f6455624ccf08c44fd4f7d8c1c4398077df3fb192
|
|
7
|
+
data.tar.gz: a5485bbe47e59950753d270fde0ffc7618ec760837b3c2f435fa4b9f798c81822e514dab1e9688a090b2d31cc13929b2ecdd4fe3038ec57db6581eecb61b18aa
|
data/.shipkit.yml
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
---
|
|
2
|
-
previous_version: 0.6.
|
|
2
|
+
previous_version: 0.6.15
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.16
|
|
4
|
+
|
|
5
|
+
- Custom filter `scope` blocks can take the operator as a second argument,
|
|
6
|
+
e.g. `scope ->(value, operator) { ... }`, so they can handle `isnt`,
|
|
7
|
+
`is_empty` and the other operators. Existing `->(value) { ... }` scopes keep
|
|
8
|
+
working unchanged.
|
|
9
|
+
|
|
10
|
+
## 0.6.15
|
|
11
|
+
|
|
12
|
+
- Custom filter `scope` blocks now work. Applied filters are built from the
|
|
13
|
+
column's `filter do ... end` definition (`scope`, `operators`, `multiple`,
|
|
14
|
+
`collection`, `having`, ...) with the requested `value` and `operator`
|
|
15
|
+
layered on top, and `Mensa::Filter#scope` returns the proc instead of
|
|
16
|
+
calling it without arguments. Host apps can remove workarounds that patch
|
|
17
|
+
`Mensa::Base#active_filters` or `Mensa::Filter#scope`.
|
|
18
|
+
- Only `value` and `operator` are taken from the request for applied filters;
|
|
19
|
+
other filter options come from the column definition.
|
|
20
|
+
- Exports are refused (403) for tables with `exportable false`, instead of
|
|
21
|
+
being created and failing in `Mensa::ExportJob`.
|
|
22
|
+
|
|
3
23
|
## 0.6.12
|
|
4
24
|
|
|
5
25
|
- Tables built with `params` (`table :name, params: {...}`) now work in filters,
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -118,6 +118,59 @@ You can show your tables on the page using the following:
|
|
|
118
118
|
Custom views are views not defined by the developer (SystemViews) but by the end-user by adding/removing filters.
|
|
119
119
|
When you enable these, they are stored in the database and can be used across sessions, by the user who created them.
|
|
120
120
|
|
|
121
|
+
### Filters
|
|
122
|
+
|
|
123
|
+
Add `filter` to a column to let users filter on it. By default Mensa compares the
|
|
124
|
+
column's attribute with the chosen value, using operators that fit the column type.
|
|
125
|
+
The filter block takes these options:
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
column(:role) do
|
|
129
|
+
filter do
|
|
130
|
+
collection -> { User::ROLES } # Values to choose from (array or proc)
|
|
131
|
+
multiple true # Allow choosing several values
|
|
132
|
+
operators [:is, :isnt] # Limit the operators users can pick
|
|
133
|
+
operator :isnt # Default operator
|
|
134
|
+
having true # Filter with HAVING, for aggregate attributes
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The operators are `is`, `isnt`, `matches`, `does_not_match`, `gt`, `gteq`, `lt`,
|
|
140
|
+
`lteq`, `is_duplicate`, `is_current`, `is_empty` and `isnt_empty`.
|
|
141
|
+
|
|
142
|
+
#### Custom filter scopes
|
|
143
|
+
|
|
144
|
+
When comparing the attribute isn't enough, give the filter a `scope`. It runs on the
|
|
145
|
+
table's scope and receives the chosen value, an array when `multiple` is set:
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
column(:account_names) do
|
|
149
|
+
attribute %((SELECT STRING_AGG(accounts.name, ', ') FROM accounts WHERE accounts.id = ANY(containers.account_ids)))
|
|
150
|
+
filter do
|
|
151
|
+
collection -> { Account.order(:name).pluck(:name) }
|
|
152
|
+
multiple true
|
|
153
|
+
operators [:is]
|
|
154
|
+
scope ->(value) { where("containers.account_ids && ARRAY[:ids]::uuid[]", ids: Account.where(name: Array(value)).pluck(:id)) }
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
To support more operators, accept the operator (a symbol) as a second argument:
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
filter do
|
|
163
|
+
operators [:is, :isnt, :is_empty]
|
|
164
|
+
scope ->(value, operator) {
|
|
165
|
+
case operator
|
|
166
|
+
when :isnt then where.not(account_id: value)
|
|
167
|
+
when :is_empty then where(account_id: nil)
|
|
168
|
+
else where(account_id: value)
|
|
169
|
+
end
|
|
170
|
+
}
|
|
171
|
+
end
|
|
172
|
+
```
|
|
173
|
+
|
|
121
174
|
### Grouping
|
|
122
175
|
|
|
123
176
|
Rows can be shown in groups, each with a header that shows the group's value and
|
|
@@ -21,6 +21,8 @@ module Mensa
|
|
|
21
21
|
# Creates a new export for the current user and enqueues the job that
|
|
22
22
|
# generates and attaches the CSV.
|
|
23
23
|
def create
|
|
24
|
+
return head :forbidden unless table.exportable?
|
|
25
|
+
|
|
24
26
|
export = Mensa::Export.new(
|
|
25
27
|
table_name: params[:table_id],
|
|
26
28
|
table_view_id: params[:table_view_id].presence,
|
|
@@ -108,6 +110,12 @@ module Mensa
|
|
|
108
110
|
@table_params ||= Mensa::TableParams.from_request(params)
|
|
109
111
|
end
|
|
110
112
|
|
|
113
|
+
def table
|
|
114
|
+
@table ||= Mensa.for_name(params[:table_id], params: table_params).tap do |table|
|
|
115
|
+
table.original_view_context = helpers
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
111
119
|
def list_stream
|
|
112
120
|
turbo_stream.replace(Mensa::Export.list_dom_id(params[:table_id], current_mensa_user, params: table_params),
|
|
113
121
|
partial: "mensa/exports/list", locals: list_locals)
|
data/app/tables/mensa/base.rb
CHANGED
|
@@ -107,12 +107,15 @@ module Mensa
|
|
|
107
107
|
columns.any?(&:filter?)
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
-
# Returns the active filters, skipping any whose column no longer exists.
|
|
111
110
|
def active_filters
|
|
112
111
|
(config[:filters] || {}).filter_map do |column_name, filter_config|
|
|
113
112
|
col = column(column_name)
|
|
114
113
|
next unless col
|
|
115
|
-
|
|
114
|
+
|
|
115
|
+
definition = config.dig(:columns, col.name, :filter)
|
|
116
|
+
definition = {} unless definition.is_a?(Hash)
|
|
117
|
+
requested = (filter_config || {}).to_h.symbolize_keys.slice(:value, :operator)
|
|
118
|
+
Mensa::Filter.new(column: col, config: definition.merge(requested), table: self)
|
|
116
119
|
end
|
|
117
120
|
end
|
|
118
121
|
|
data/app/tables/mensa/filter.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Mensa
|
|
|
10
10
|
|
|
11
11
|
config_reader :operator, cast: :to_sym
|
|
12
12
|
config_reader :value
|
|
13
|
-
config_reader :scope
|
|
13
|
+
config_reader :scope, call: false
|
|
14
14
|
config_reader :multiple
|
|
15
15
|
config_reader :having?
|
|
16
16
|
|
|
@@ -80,7 +80,7 @@ module Mensa
|
|
|
80
80
|
|
|
81
81
|
def filter_scope(record_scope)
|
|
82
82
|
if scope
|
|
83
|
-
record_scope.instance_exec(
|
|
83
|
+
record_scope.instance_exec(*scope_arguments, &scope)
|
|
84
84
|
else
|
|
85
85
|
return apply_duplicate_filter(record_scope) if operator == :is_duplicate
|
|
86
86
|
|
|
@@ -88,7 +88,7 @@ module Mensa
|
|
|
88
88
|
return record_scope if value.is_a?(Array) && value.compact_blank.empty?
|
|
89
89
|
|
|
90
90
|
query, hash = query_and_hash_for_operator
|
|
91
|
-
record_scope = (
|
|
91
|
+
record_scope = (having? ? record_scope.having(query, hash) : record_scope.where(query, hash)) if query.present?
|
|
92
92
|
record_scope
|
|
93
93
|
end
|
|
94
94
|
end
|
|
@@ -182,6 +182,17 @@ module Mensa
|
|
|
182
182
|
end
|
|
183
183
|
end
|
|
184
184
|
|
|
185
|
+
# Arguments for a custom filter scope: the value and the operator. Lambdas
|
|
186
|
+
# only get as many as they declare, so `->(value) { ... }` keeps working
|
|
187
|
+
# next to `->(value, operator) { ... }`. Plain procs ignore extra arguments.
|
|
188
|
+
def scope_arguments
|
|
189
|
+
args = [normalize(value), operator]
|
|
190
|
+
return args unless scope.lambda?
|
|
191
|
+
return args if scope.parameters.any? { |type, _| type == :rest }
|
|
192
|
+
|
|
193
|
+
args.first(scope.parameters.count { |type, _| type == :req || type == :opt })
|
|
194
|
+
end
|
|
195
|
+
|
|
185
196
|
def label_for_value(selected_value, options)
|
|
186
197
|
option = options.find { |_label, value| value.to_s == selected_value.to_s }
|
|
187
198
|
option ? option.first : selected_value
|
data/lib/mensa/version.rb
CHANGED
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.6.
|
|
4
|
+
version: 0.6.16
|
|
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-10-
|
|
11
|
+
date: 2026-10-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|