mensa 0.9.5 → 0.9.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.
- checksums.yaml +4 -4
- data/.devcontainer/devcontainer-lock.json +4 -4
- data/.devcontainer/devcontainer.json +16 -7
- data/.devcontainer/docker-compose.yml +74 -13
- data/.devcontainer/env.conf +29 -0
- data/.devcontainer/postStart.sh +7 -2
- data/.gitignore +2 -1
- data/.shipkit.yml +1 -1
- data/.worktreeinclude +2 -0
- data/Gemfile.lock +1 -1
- data/README.md +56 -4
- data/app/components/mensa/add_filter/component.css +9 -0
- data/app/components/mensa/add_filter/component_controller.js +55 -2
- data/app/components/mensa/filter_pill/component.rb +1 -7
- data/app/components/mensa/filter_pill_list/component_controller.js +1 -6
- data/app/tables/mensa/base.rb +1 -1
- data/app/tables/mensa/config/table_dsl.rb +23 -0
- data/app/tables/mensa/config/view_dsl.rb +19 -0
- data/app/tables/mensa/filter.rb +51 -5
- data/app/views/mensa/tables/filters/show.turbo_stream.erb +15 -8
- data/bin/de +868 -0
- data/config/locales/en.yml +5 -0
- data/config/locales/nl.yml +5 -0
- data/lib/mensa/verifier.rb +2 -0
- data/lib/mensa/version.rb +1 -1
- data/mise.toml +1 -3
- metadata +4 -2
- data/.devcontainer/initialize.sh +0 -22
data/app/tables/mensa/filter.rb
CHANGED
|
@@ -16,7 +16,7 @@ module Mensa
|
|
|
16
16
|
|
|
17
17
|
# Types that ILIKE works on, nil is an attribute without a type
|
|
18
18
|
TEXT_TYPES = [:string, :text, :citext, nil].freeze
|
|
19
|
-
# Types with a meaningful order, for gt, gteq, lt and
|
|
19
|
+
# Types with a meaningful order, for gt, gteq, lt, lteq and between
|
|
20
20
|
RANGE_TYPES = %i[integer bigint float decimal money date datetime timestamp timestamptz time interval].freeze
|
|
21
21
|
# Types where an exact match on a value is of little use
|
|
22
22
|
POINT_IN_TIME_TYPES = %i[date datetime timestamp timestamptz].freeze
|
|
@@ -34,12 +34,24 @@ module Mensa
|
|
|
34
34
|
[:gteq, I18n.t("mensa.operators.gteq"), true],
|
|
35
35
|
[:lt, I18n.t("mensa.operators.lt"), true],
|
|
36
36
|
[:lteq, I18n.t("mensa.operators.lteq"), true],
|
|
37
|
+
[:between, I18n.t("mensa.operators.between"), true],
|
|
37
38
|
[:is_duplicate, I18n.t("mensa.operators.is_duplicate"), false],
|
|
38
39
|
[:is_current, I18n.t("mensa.operators.is_current"), false],
|
|
39
40
|
[:is_empty, I18n.t("mensa.operators.is_empty"), false],
|
|
40
41
|
[:isnt_empty, I18n.t("mensa.operators.isnt_empty"), false]
|
|
41
42
|
].freeze
|
|
42
43
|
end
|
|
44
|
+
|
|
45
|
+
# A value in a form to compare filters with, e.g. a view's with the
|
|
46
|
+
# current one. The ends of a range keep their place, other values are a set.
|
|
47
|
+
def comparable_value(operator, value)
|
|
48
|
+
if operator&.to_sym == :between
|
|
49
|
+
from, to = Array(value)
|
|
50
|
+
return [from.to_s, to.to_s]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
Array(value).map(&:to_s).reject(&:blank?).sort
|
|
54
|
+
end
|
|
43
55
|
end
|
|
44
56
|
|
|
45
57
|
def initialize(column:, config:, table:)
|
|
@@ -80,7 +92,13 @@ module Mensa
|
|
|
80
92
|
def formatted_value
|
|
81
93
|
options = collection_options
|
|
82
94
|
|
|
83
|
-
if
|
|
95
|
+
if operator == :between
|
|
96
|
+
from, to = range_values.map { |entry| label_for_value(entry, options) }
|
|
97
|
+
return from if to.blank?
|
|
98
|
+
return to if from.blank?
|
|
99
|
+
|
|
100
|
+
I18n.t("mensa.filters.between_value", from: from, to: to)
|
|
101
|
+
elsif value.is_a?(Array)
|
|
84
102
|
value.map { |entry| label_for_value(entry, options) }.join(", ")
|
|
85
103
|
else
|
|
86
104
|
label_for_value(value, options)
|
|
@@ -112,11 +130,11 @@ module Mensa
|
|
|
112
130
|
else
|
|
113
131
|
operators.delete_if { |op| op[0] == :is_current } unless Current.method_defined?(column.name, false)
|
|
114
132
|
type = column.type
|
|
115
|
-
operators.delete_if { |op| [:matches, :does_not_match].include?(op[0]) } if collection.present?
|
|
133
|
+
operators.delete_if { |op| [:matches, :does_not_match, :between].include?(op[0]) } if collection.present?
|
|
116
134
|
# Only these operators work for the column's type in SQL, the others
|
|
117
135
|
# raise, e.g. LIKE on a boolean
|
|
118
136
|
operators.delete_if { |op| [:matches, :does_not_match].include?(op[0]) } unless TEXT_TYPES.include?(type)
|
|
119
|
-
operators.delete_if { |op| [:gt, :lt, :gteq, :lteq].include?(op[0]) } unless RANGE_TYPES.include?(type)
|
|
137
|
+
operators.delete_if { |op| [:gt, :lt, :gteq, :lteq, :between].include?(op[0]) } unless RANGE_TYPES.include?(type)
|
|
120
138
|
operators.delete_if { |op| [:is, :isnt].include?(op[0]) } if POINT_IN_TIME_TYPES.include?(type) || STRUCTURED_TYPES.include?(type)
|
|
121
139
|
# json has no equality, so duplicates can't be grouped
|
|
122
140
|
operators.delete_if { |op| op[0] == :is_duplicate } if type == :json
|
|
@@ -127,6 +145,8 @@ module Mensa
|
|
|
127
145
|
# Used in the where clause
|
|
128
146
|
def query_and_hash_for_operator
|
|
129
147
|
col = "(#{column.attribute_for_condition})"
|
|
148
|
+
return range_query_and_hash(col) if operator == :between
|
|
149
|
+
|
|
130
150
|
hash = {value: normalize(value)}
|
|
131
151
|
hash[:value] = hash[:value].compact_blank if hash[:value].is_a?(Array)
|
|
132
152
|
|
|
@@ -163,8 +183,19 @@ module Mensa
|
|
|
163
183
|
[query, hash]
|
|
164
184
|
end
|
|
165
185
|
|
|
186
|
+
# A range with one end open reads as the comparison it is
|
|
166
187
|
def operator_label
|
|
167
|
-
|
|
188
|
+
label_operator = operator
|
|
189
|
+
if operator == :between
|
|
190
|
+
from, to = range_values
|
|
191
|
+
label_operator = :gteq if to.blank? && from.present?
|
|
192
|
+
label_operator = :lteq if from.blank? && to.present?
|
|
193
|
+
end
|
|
194
|
+
Mensa::Filter.OPERATORS.find { |op| op[0] == label_operator }[1]
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def comparable_value
|
|
198
|
+
self.class.comparable_value(operator, value)
|
|
168
199
|
end
|
|
169
200
|
|
|
170
201
|
def operator_with_value?
|
|
@@ -188,6 +219,21 @@ module Mensa
|
|
|
188
219
|
|
|
189
220
|
private
|
|
190
221
|
|
|
222
|
+
# The from and to of a between filter, either can be blank for an open end
|
|
223
|
+
def range_values
|
|
224
|
+
from, to = Array(value)
|
|
225
|
+
[from.presence, to.presence]
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Both ends are inclusive, a blank end leaves that side open
|
|
229
|
+
def range_query_and_hash(col)
|
|
230
|
+
from, to = range_values.map { |entry| normalize(entry) }
|
|
231
|
+
conditions = []
|
|
232
|
+
conditions << "#{col} >= :from" if from.present?
|
|
233
|
+
conditions << "#{col} <= :to" if to.present?
|
|
234
|
+
[conditions.join(" AND "), {from: from, to: to}]
|
|
235
|
+
end
|
|
236
|
+
|
|
191
237
|
def validate_operators!
|
|
192
238
|
valid_keys = Mensa::Filter.OPERATORS.map(&:first)
|
|
193
239
|
|
|
@@ -28,14 +28,21 @@
|
|
|
28
28
|
<% end %>
|
|
29
29
|
</ul>
|
|
30
30
|
<% else %>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
<% range = @column.filter.operators.any? { |operator_name, *| operator_name == :between } %>
|
|
32
|
+
<% between = range && @operator == "between" %>
|
|
33
|
+
<div class="mensa-table__add_filter__popover_container__range" data-range="<%= 'true' if between %>">
|
|
34
|
+
<% [[:value, @values.first, t("mensa.filters.from")], ([:valueTo, (@values.second if between), t("mensa.filters.to")] if range)].compact.each do |target, value, placeholder| %>
|
|
35
|
+
<input class="mensa-table__add_filter__popover_container__input"
|
|
36
|
+
type="<%= @column.filter.input_type %>"
|
|
37
|
+
value="<%= value %>"
|
|
38
|
+
autocomplete="off"
|
|
39
|
+
inputmode="<%= @column.type == :integer ? 'numeric' : nil %>"
|
|
40
|
+
step="<%= @column.type == :integer ? 1 : (@column.type == :datetime ? 1 : nil) %>"
|
|
41
|
+
<% if range %>placeholder="<%= placeholder if target == :valueTo || between %>" data-range-placeholder="<%= placeholder %>"<% end %>
|
|
42
|
+
data-mensa-add-filter-target="<%= target %>"
|
|
43
|
+
data-action="input->mensa-add-filter#manualValueChanged keydown.enter->mensa-add-filter#applyManualValue">
|
|
44
|
+
<% end %>
|
|
45
|
+
</div>
|
|
39
46
|
<% end %>
|
|
40
47
|
<hr class="mensa-table__add_filter__popover_container__separator">
|
|
41
48
|
<% end %>
|