mensa 0.2.0 → 0.2.2
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 -0
- data/Gemfile.lock +14 -1
- data/README.md +7 -3
- data/app/components/mensa/add_filter/component_controller.js +12 -8
- data/app/components/mensa/filter/component_controller.js +12 -0
- data/app/components/mensa/{filters → filter_list}/component.html.slim +2 -2
- data/app/components/mensa/{filters → filter_list}/component.rb +2 -2
- data/app/components/mensa/{filters → filter_list}/component_controller.js +2 -2
- data/app/components/mensa/row_action/component.html.slim +1 -1
- data/app/components/mensa/table/component.html.slim +2 -2
- data/app/components/mensa/table/component_controller.js +8 -6
- data/app/javascript/mensa/controllers/index.js +5 -2
- data/app/tables/mensa/action.rb +4 -2
- data/app/tables/mensa/base.rb +3 -4
- data/app/tables/mensa/column.rb +10 -2
- data/app/tables/mensa/config/action_dsl.rb +3 -0
- data/app/tables/mensa/config/column_dsl.rb +4 -4
- data/app/tables/mensa/config/dsl_logic.rb +7 -1
- data/app/tables/mensa/config/filter_dsl.rb +2 -0
- data/app/tables/mensa/config/table_dsl.rb +2 -2
- data/app/tables/mensa/config_readers.rb +5 -3
- data/app/tables/mensa/filter.rb +33 -4
- data/app/tables/mensa/scope.rb +3 -18
- data/app/views/mensa/tables/show.turbo_stream.slim +1 -1
- data/lib/mensa/version.rb +1 -1
- data/mensa.gemspec +3 -0
- metadata +21 -6
- /data/app/components/mensa/{filters → filter_list}/component.css +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e79f4a4d3a4be038ed02e0f7dd30fee1abf0b6945b1a5817f05103928c288296
|
|
4
|
+
data.tar.gz: 888bdc7e9aeead37ec6f0461b7bcedd4a63905eaad8a75a4f57b698c88d8a05f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b8d4acf77c6ed877a58ad145cd522fa50fccf770336f13e657c312c7d04a2a1e0b9eb37c9d6d7a16745c17924d3969deb6777921280834e31fa4a45cd29d644
|
|
7
|
+
data.tar.gz: b8053f1def913871788a7f3e2530e4ff7946e241af8c258d1a392b637aabad9bc3c40eaa0b71ab34c7454d2b1091346e2683b1a93e1f299af11845e28aecc886
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -17,7 +17,7 @@ GIT
|
|
|
17
17
|
PATH
|
|
18
18
|
remote: .
|
|
19
19
|
specs:
|
|
20
|
-
mensa (0.1
|
|
20
|
+
mensa (0.2.1)
|
|
21
21
|
caxlsx_rails (~> 0)
|
|
22
22
|
importmap-rails
|
|
23
23
|
pagy (>= 43)
|
|
@@ -133,6 +133,9 @@ GEM
|
|
|
133
133
|
connection_pool (2.5.4)
|
|
134
134
|
crass (1.0.6)
|
|
135
135
|
date (3.5.0)
|
|
136
|
+
debug (1.11.0)
|
|
137
|
+
irb (~> 1.10)
|
|
138
|
+
reline (>= 0.3.8)
|
|
136
139
|
diffy (3.4.4)
|
|
137
140
|
drb (2.2.3)
|
|
138
141
|
erb (5.1.3)
|
|
@@ -286,6 +289,14 @@ GEM
|
|
|
286
289
|
actionpack (>= 6.1)
|
|
287
290
|
activesupport (>= 6.1)
|
|
288
291
|
sprockets (>= 3.0.0)
|
|
292
|
+
sqlite3 (2.8.0-aarch64-linux-gnu)
|
|
293
|
+
sqlite3 (2.8.0-aarch64-linux-musl)
|
|
294
|
+
sqlite3 (2.8.0-arm-linux-gnu)
|
|
295
|
+
sqlite3 (2.8.0-arm-linux-musl)
|
|
296
|
+
sqlite3 (2.8.0-arm64-darwin)
|
|
297
|
+
sqlite3 (2.8.0-x86_64-darwin)
|
|
298
|
+
sqlite3 (2.8.0-x86_64-linux-gnu)
|
|
299
|
+
sqlite3 (2.8.0-x86_64-linux-musl)
|
|
289
300
|
stimulus-rails (1.3.4)
|
|
290
301
|
railties (>= 6.0.0)
|
|
291
302
|
stringio (3.1.7)
|
|
@@ -338,6 +349,7 @@ PLATFORMS
|
|
|
338
349
|
|
|
339
350
|
DEPENDENCIES
|
|
340
351
|
capybara (~> 3.40)
|
|
352
|
+
debug
|
|
341
353
|
mensa!
|
|
342
354
|
pry
|
|
343
355
|
puma
|
|
@@ -345,6 +357,7 @@ DEPENDENCIES
|
|
|
345
357
|
selenium-webdriver (~> 4.17)
|
|
346
358
|
slim (~> 5.2)
|
|
347
359
|
sprockets-rails
|
|
360
|
+
sqlite3 (~> 2.8)
|
|
348
361
|
|
|
349
362
|
BUNDLED WITH
|
|
350
363
|
2.6.2
|
data/README.md
CHANGED
|
@@ -9,8 +9,12 @@ Wanted features:
|
|
|
9
9
|
- [x] sorting
|
|
10
10
|
- [x] tables without headers (and without most of the above)
|
|
11
11
|
- [ ] column sorting
|
|
12
|
-
- [
|
|
12
|
+
- [x] filtering of multiple columns
|
|
13
|
+
- [ ] editing of existing filters
|
|
13
14
|
- [ ] view selection and exports per view
|
|
15
|
+
|
|
16
|
+
optionally:
|
|
17
|
+
|
|
14
18
|
- [ ] group by
|
|
15
19
|
- [ ] sum/max/min
|
|
16
20
|
- [ ] tables backed by arrays (of ActiveModel)
|
|
@@ -37,7 +41,6 @@ class UserTable < ApplicationTable
|
|
|
37
41
|
sortable true
|
|
38
42
|
sanitize true
|
|
39
43
|
internal false
|
|
40
|
-
method nil
|
|
41
44
|
visible true
|
|
42
45
|
filter do
|
|
43
46
|
collection -> { }
|
|
@@ -51,6 +54,7 @@ class UserTable < ApplicationTable
|
|
|
51
54
|
|
|
52
55
|
# You can add one or more actions to a row
|
|
53
56
|
action :delete do
|
|
57
|
+
title "Delete row"
|
|
54
58
|
link { |user| user_path(user) }
|
|
55
59
|
icon "fa-regular fa-trash"
|
|
56
60
|
link_attributes data: {"turbo-confirm": "Are you sure you want to delete the user?", "turbo-method": :delete}
|
|
@@ -77,7 +81,7 @@ You can show your tables on the page using the following:
|
|
|
77
81
|
#### Views
|
|
78
82
|
|
|
79
83
|
Initial support for views is there, but pretty rudimentary:
|
|
80
|
-
`Mensa::TableView.create(table: "users", name: "Guests", data: {filters: {role: "guest"}})`
|
|
84
|
+
`Mensa::TableView.create(table: "users", name: "Guests", data: {filters: {role: {value: "guest"}}})`
|
|
81
85
|
|
|
82
86
|
### Fast
|
|
83
87
|
|
|
@@ -16,7 +16,7 @@ export default class AddFilterComponentController extends ApplicationController
|
|
|
16
16
|
supportsViews: Boolean
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
connect
|
|
19
|
+
connect() {
|
|
20
20
|
super.connect()
|
|
21
21
|
|
|
22
22
|
// this.filterValueEntered = debounce(this.filterValueEntered, 500).bind(this)
|
|
@@ -25,12 +25,12 @@ export default class AddFilterComponentController extends ApplicationController
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// Called when you click add-filter
|
|
28
|
-
toggle
|
|
28
|
+
toggle(event) {
|
|
29
29
|
this.filterListTarget.classList.toggle('hidden')
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// Called when you selected a column
|
|
33
|
-
openValuePopover
|
|
33
|
+
openValuePopover(event) {
|
|
34
34
|
let url = this.ourUrl
|
|
35
35
|
url.pathname += `/filters/${this.selectedFilterColumn}`
|
|
36
36
|
url.searchParams.append('target', this.valuePopoverTarget.id)
|
|
@@ -43,7 +43,7 @@ export default class AddFilterComponentController extends ApplicationController
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// Called when you select a column from the "dropdown"
|
|
46
|
-
selectColumn
|
|
46
|
+
selectColumn(event) {
|
|
47
47
|
this.filterListItemTargets.forEach((lt) => {
|
|
48
48
|
let check = lt.querySelector('.check')
|
|
49
49
|
check.classList.add('hidden')
|
|
@@ -60,22 +60,26 @@ export default class AddFilterComponentController extends ApplicationController
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// Called when you entered/selected a filter value
|
|
63
|
-
filterValueEntered
|
|
63
|
+
filterValueEntered(event) {
|
|
64
64
|
this.valuePopoverTarget.classList.add('hidden')
|
|
65
65
|
|
|
66
66
|
let url = this.ourUrl
|
|
67
67
|
|
|
68
68
|
let filters = url.searchParams.get('filters') || {}
|
|
69
|
+
this.mensaTableOutlet.mensaFilterOutlets.forEach((filterOutlet) => {
|
|
70
|
+
url.searchParams.append(`filters[${filterOutlet.columnNameValue}][value]`, filterOutlet.valueValue)
|
|
71
|
+
url.searchParams.append(`filters[${filterOutlet.columnNameValue}][operator]`, filterOutlet.operatorValue)
|
|
72
|
+
})
|
|
69
73
|
// FIXME: Needs better way of getting value
|
|
70
|
-
url.searchParams.append(`filters[${this.selectedFilterColumn}]`, event.target.value)
|
|
74
|
+
url.searchParams.append(`filters[${this.selectedFilterColumn}][value]`, event.target.value)
|
|
71
75
|
|
|
72
76
|
get(url, {
|
|
73
77
|
responseKind: 'turbo-stream'
|
|
74
78
|
}).then(() => {
|
|
75
79
|
// FIXME: There should be a better way to do this, possibly using
|
|
76
|
-
// this.mensaTableOutlet.
|
|
80
|
+
// this.mensaTableOutlet.filterListTarget.addEventListener("turbo:after-stream-render", this.unhide.bind(this)) ?
|
|
77
81
|
setTimeout(() => {
|
|
78
|
-
this.mensaTableOutlet.
|
|
82
|
+
this.mensaTableOutlet.filterListTarget.classList.remove('hidden')
|
|
79
83
|
}, 50)
|
|
80
84
|
})
|
|
81
85
|
event.preventDefault()
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ApplicationController from 'mensa/controllers/application_controller'
|
|
2
|
+
|
|
3
|
+
export default class FilterComponentController extends ApplicationController {
|
|
4
|
+
static values = {
|
|
5
|
+
columnName: String,
|
|
6
|
+
operator: String,
|
|
7
|
+
value: String,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
connect() {
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
.mensa-table__filters.hidden data-mensa-table-target="
|
|
1
|
+
.mensa-table__filters.hidden data-mensa-table-target="filterList"
|
|
2
2
|
.block
|
|
3
3
|
nav
|
|
4
4
|
.flex.space-x-2.overflow-none.whitespace-nowrap.scroll-p-0[aria-label="Tabs"]
|
|
5
5
|
/ existing filters first
|
|
6
6
|
- table.active_filters.each do |filter|
|
|
7
|
-
.relative
|
|
7
|
+
.relative data-controller="mensa-filter" data-mensa-filter-column-name-value=filter.column.name data-mensa-filter-value-value=filter.value data-mensa-filter-operator-value=filter.operator
|
|
8
8
|
button.relative.w-full.cursor-default.rounded-md.bg-white.dark:bg-gray-800.py-1.5.pl-3.text-left.text-gray-900.dark:text-gray-400.shadow-sm.ring-1.ring-inset.ring-gray-300.dark:ring-gray-600.focus:outline-none.focus:ring-2.focus:ring-primary-600.sm:text-sm.sm:leading-6[type="button" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label"]
|
|
9
9
|
span.block.truncate.pr-6
|
|
10
10
|
= filter
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ApplicationController from 'mensa/controllers/application_controller'
|
|
2
2
|
|
|
3
|
-
export default class
|
|
3
|
+
export default class FilterListComponentController extends ApplicationController {
|
|
4
4
|
static targets = [
|
|
5
5
|
'list',
|
|
6
6
|
]
|
|
@@ -8,7 +8,7 @@ export default class FiltersComponentController extends ApplicationController {
|
|
|
8
8
|
supportsViews: Boolean
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
connect
|
|
11
|
+
connect() {
|
|
12
12
|
super.connect()
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
- if action.show.call(row.record)
|
|
2
|
-
a href=(action.link ? table.original_view_context.instance_exec(row.record, &action.link) : '') title=action.
|
|
2
|
+
a href=(action.link ? table.original_view_context.instance_exec(row.record, &action.link) : '') title=action.title *action.link_attributes
|
|
3
3
|
- if action.icon
|
|
4
4
|
i.fa class=action.icon
|
|
5
5
|
- else
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
.mensa-table id="table-#{table.table_id}" data-mensa-table-view-condensed-value="#{table.view_condensed?}" data-mensa-table-supports-views-value="#{table.supports_views?}" data-controller="mensa-table"
|
|
1
|
+
.mensa-table id="table-#{table.table_id}" data-mensa-table-view-condensed-value="#{table.view_condensed?}" data-mensa-table-supports-views-value="#{table.supports_views?}" data-controller="mensa-table" data-mensa-table-mensa-filter-outlet="[data-controller='mensa-filter']"
|
|
2
2
|
= render Mensa::Search::Component.new(table: table)
|
|
3
3
|
div id="filters-#{table.table_id}"
|
|
4
|
-
= render Mensa::
|
|
4
|
+
= render Mensa::FilterList::Component.new(table: table)
|
|
5
5
|
- if table.supports_views? && table.show_header?
|
|
6
6
|
= render Mensa::Views::Component.new(table: table)
|
|
7
7
|
turbo-frame id=table.table_id src=helpers.mensa.table_path(table.name, {turbo_frame_id: table.table_id}.merge(params)) target="_top" loading="lazy" data-mensa-table-target="turboFrame"
|
|
@@ -2,10 +2,12 @@ import ApplicationController from "mensa/controllers/application_controller";
|
|
|
2
2
|
import { get } from "@rails/request.js";
|
|
3
3
|
|
|
4
4
|
export default class TableComponentController extends ApplicationController {
|
|
5
|
+
static outlets = ["mensa-filter"]
|
|
6
|
+
|
|
5
7
|
static targets = [
|
|
6
8
|
"controlBar", // Bar with buttons
|
|
7
9
|
"condenseExpandIcon", // Icon
|
|
8
|
-
"
|
|
10
|
+
"filterList", // Tabs or list of filters
|
|
9
11
|
"views", // Tabs or list of views
|
|
10
12
|
"viewButtons", // Cancel and save buttons for views
|
|
11
13
|
"search", // Search bar
|
|
@@ -27,11 +29,11 @@ export default class TableComponentController extends ApplicationController {
|
|
|
27
29
|
this.viewButtonsTarget.classList.remove("hidden");
|
|
28
30
|
this.searchTarget.classList.remove("hidden");
|
|
29
31
|
this.viewsTarget.classList.add("hidden");
|
|
30
|
-
this.
|
|
32
|
+
this.filterListTarget.classList.remove("hidden");
|
|
31
33
|
} else {
|
|
32
34
|
this.controlBarTarget.classList.add("hidden");
|
|
33
35
|
this.viewButtonsTarget.classList.remove("hidden");
|
|
34
|
-
this.
|
|
36
|
+
this.filterListTarget.classList.remove("hidden");
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -41,12 +43,12 @@ export default class TableComponentController extends ApplicationController {
|
|
|
41
43
|
if (this.supportsViewsValue) {
|
|
42
44
|
this.searchTarget.classList.add("hidden");
|
|
43
45
|
this.viewButtonsTarget.classList.add("hidden");
|
|
44
|
-
this.
|
|
46
|
+
this.filterListTarget.classList.add("hidden");
|
|
45
47
|
this.viewsTarget.classList.remove("hidden");
|
|
46
48
|
} else {
|
|
47
49
|
this.controlBarTarget.classList.remove("hidden");
|
|
48
50
|
this.viewButtonsTarget.classList.add("hidden");
|
|
49
|
-
this.
|
|
51
|
+
this.filterListTarget.classList.add("hidden");
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
|
|
@@ -73,6 +75,6 @@ export default class TableComponentController extends ApplicationController {
|
|
|
73
75
|
|
|
74
76
|
let url = this.ourUrl;
|
|
75
77
|
url.pathname += ".xlsx";
|
|
76
|
-
get(url, {}).then(() => {});
|
|
78
|
+
get(url, {}).then(() => { });
|
|
77
79
|
}
|
|
78
80
|
}
|
|
@@ -6,8 +6,11 @@ import { application } from "mensa/controllers/application"
|
|
|
6
6
|
import AddFilterComponentController from "mensa/components/add_filter/component_controller";
|
|
7
7
|
application.register("mensa-add-filter", AddFilterComponentController);
|
|
8
8
|
|
|
9
|
-
import
|
|
10
|
-
application.register("mensa-
|
|
9
|
+
import FilterComponentController from "mensa/components/filter/component_controller";
|
|
10
|
+
application.register("mensa-filter", FilterComponentController);
|
|
11
|
+
|
|
12
|
+
import FilterListComponentController from "mensa/components/filter_list/component_controller";
|
|
13
|
+
application.register("mensa-filter-list", FilterListComponentController);
|
|
11
14
|
|
|
12
15
|
import SearchComponentController from "mensa/components/search/component_controller";
|
|
13
16
|
application.register("mensa-search", SearchComponentController);
|
data/app/tables/mensa/action.rb
CHANGED
|
@@ -18,9 +18,11 @@ module Mensa
|
|
|
18
18
|
@config = config
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
config_reader :
|
|
21
|
+
config_reader :title
|
|
22
|
+
config_reader :link, call: false
|
|
22
23
|
config_reader :link_attributes
|
|
23
24
|
config_reader :icon
|
|
24
|
-
config_reader :show
|
|
25
|
+
config_reader :show, call: false
|
|
26
|
+
|
|
25
27
|
end
|
|
26
28
|
end
|
data/app/tables/mensa/base.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Mensa
|
|
|
9
9
|
attr_reader :config, :params
|
|
10
10
|
|
|
11
11
|
config_reader :model
|
|
12
|
-
config_reader :link
|
|
12
|
+
config_reader :link, call: false
|
|
13
13
|
config_reader :supports_views?
|
|
14
14
|
config_reader :supports_custom_views?
|
|
15
15
|
config_reader :supports_filters?
|
|
@@ -31,8 +31,6 @@ module Mensa
|
|
|
31
31
|
|
|
32
32
|
# Returns all columns
|
|
33
33
|
def columns
|
|
34
|
-
return @columns if @columns
|
|
35
|
-
|
|
36
34
|
@columns ||= column_order.map { |column_name| Mensa::Column.new(column_name, config: config.dig(:columns, column_name), table: self) }
|
|
37
35
|
end
|
|
38
36
|
|
|
@@ -56,6 +54,7 @@ module Mensa
|
|
|
56
54
|
ordered_scope.map { |row| Mensa::Row.new(self, row) }
|
|
57
55
|
end
|
|
58
56
|
|
|
57
|
+
# Returns true if the table has filters
|
|
59
58
|
def filters?
|
|
60
59
|
columns.any?(&:filter?)
|
|
61
60
|
end
|
|
@@ -87,7 +86,7 @@ module Mensa
|
|
|
87
86
|
end
|
|
88
87
|
|
|
89
88
|
def active_filters
|
|
90
|
-
(config[:filters] || {}).map { |column_name,
|
|
89
|
+
(config[:filters] || {}).map { |column_name, filter_config| Mensa::Filter.new(column: column(column_name), config: filter_config, table: self) }
|
|
91
90
|
end
|
|
92
91
|
|
|
93
92
|
def table_id
|
data/app/tables/mensa/column.rb
CHANGED
|
@@ -7,8 +7,8 @@ module Mensa
|
|
|
7
7
|
|
|
8
8
|
def initialize(name, config:, table:)
|
|
9
9
|
@name = name
|
|
10
|
+
@config = self.class.definition.merge(config || {})
|
|
10
11
|
@table = table
|
|
11
|
-
@config = config
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
config_reader :sortable?
|
|
@@ -55,6 +55,7 @@ module Mensa
|
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
+
# Returns true if the column supports filtering
|
|
58
59
|
def filter?
|
|
59
60
|
config.key?(:filter)
|
|
60
61
|
end
|
|
@@ -62,7 +63,7 @@ module Mensa
|
|
|
62
63
|
def filter
|
|
63
64
|
return unless filter?
|
|
64
65
|
|
|
65
|
-
@filter ||= Mensa::Filter.new(
|
|
66
|
+
@filter ||= Mensa::Filter.new(column: self, config: table.config.dig(:filters, name) || {}, table: table)
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
def human_name
|
|
@@ -81,5 +82,12 @@ module Mensa
|
|
|
81
82
|
end
|
|
82
83
|
end
|
|
83
84
|
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
class << self
|
|
88
|
+
def definition(&)
|
|
89
|
+
@definition ||= Mensa::Config::ColumnDsl.new(self.name, &).config
|
|
90
|
+
end
|
|
91
|
+
end
|
|
84
92
|
end
|
|
85
93
|
end
|
|
@@ -4,9 +4,12 @@ module Mensa::Config
|
|
|
4
4
|
class ActionDsl
|
|
5
5
|
include DslLogic
|
|
6
6
|
|
|
7
|
+
option :title, default: ->() { name }
|
|
7
8
|
option :icon
|
|
8
9
|
option :show, default: ->(record) { true }
|
|
9
10
|
option :link
|
|
10
11
|
option :link_attributes, default: {}
|
|
12
|
+
|
|
13
|
+
delegate :t, to: :I18n
|
|
11
14
|
end
|
|
12
15
|
end
|
|
@@ -13,11 +13,11 @@ module Mensa::Config
|
|
|
13
13
|
option :attribute
|
|
14
14
|
# Internal columns will never be shown, but are there to be selected, to be used in methods
|
|
15
15
|
# Mensa doesn't select the whole records, to only select what we need
|
|
16
|
-
option :internal
|
|
16
|
+
option :internal, default: false
|
|
17
17
|
option :method
|
|
18
18
|
|
|
19
|
-
option :visible, default:
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
option :visible, default: true
|
|
20
|
+
option :render, dsl: Mensa::Config::RenderDsl
|
|
21
|
+
option :filter, dsl: Mensa::Config::FilterDsl
|
|
22
22
|
end
|
|
23
23
|
end
|
|
@@ -29,6 +29,8 @@ module Mensa::Config
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
private
|
|
33
|
+
|
|
32
34
|
###
|
|
33
35
|
# Define a accessor method
|
|
34
36
|
#
|
|
@@ -54,7 +56,7 @@ module Mensa::Config
|
|
|
54
56
|
# config[:render] = Mensa::RenderDsl.new(name, &).config
|
|
55
57
|
# end
|
|
56
58
|
#
|
|
57
|
-
# by calling
|
|
59
|
+
# by calling option :render, dsl: Mensa::RenderDsl
|
|
58
60
|
#
|
|
59
61
|
def dsl_option(option_name, klass)
|
|
60
62
|
define_method(option_name) do |name = nil, &block|
|
|
@@ -62,6 +64,10 @@ module Mensa::Config
|
|
|
62
64
|
end
|
|
63
65
|
end
|
|
64
66
|
|
|
67
|
+
###
|
|
68
|
+
# Define a DSL hash
|
|
69
|
+
# by calling option :action, dsl: Mensa::ActionDsl
|
|
70
|
+
#
|
|
65
71
|
def dsl_hash(option_name, klass, config_name:)
|
|
66
72
|
config_name = config_name || option_name.to_s.pluralize.to_sym
|
|
67
73
|
|
|
@@ -48,7 +48,7 @@ module Mensa::Config
|
|
|
48
48
|
class TableDsl
|
|
49
49
|
include DslLogic
|
|
50
50
|
|
|
51
|
-
option :model, default: -> { self.class.name.demodulize.to_s.classify.constantize rescue raise "No model found for #{self.class.name}" }
|
|
51
|
+
option :model, default: -> { self.class.name.demodulize.to_s.classify.gsub("Table","").singularize.constantize rescue raise "No model found for #{self.class.name}" }
|
|
52
52
|
option :column, dsl_hash: Mensa::Config::ColumnDsl
|
|
53
53
|
option :internal, dsl_hash: Mensa::Config::ColumnDsl, default: {internal: true}
|
|
54
54
|
option :link
|
|
@@ -65,7 +65,7 @@ module Mensa::Config
|
|
|
65
65
|
# Actions
|
|
66
66
|
option :action, dsl_hash: Mensa::Config::ActionDsl
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
option :render, dsl: Mensa::Config::RenderDsl
|
|
69
69
|
|
|
70
70
|
option :supports_views, default: false
|
|
71
71
|
option :supports_custom_views, default: false
|
|
@@ -3,11 +3,13 @@ module Mensa
|
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
5
|
class_methods do
|
|
6
|
-
|
|
6
|
+
# Set call to false to avoid immediate execution of Procs
|
|
7
|
+
def config_reader(name, call: true)
|
|
7
8
|
define_method name do
|
|
8
|
-
config[name.to_s.gsub("?", "").to_sym]
|
|
9
|
+
value = config[name.to_s.gsub("?", "").to_sym]
|
|
10
|
+
call == true && value.is_a?(Proc) ? instance_exec(&value) : value
|
|
9
11
|
end
|
|
10
12
|
end
|
|
11
13
|
end
|
|
12
14
|
end
|
|
13
|
-
end
|
|
15
|
+
end
|
data/app/tables/mensa/filter.rb
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
module Mensa
|
|
4
4
|
class Filter
|
|
5
5
|
include ConfigReaders
|
|
6
|
-
attr_reader :column, :
|
|
6
|
+
attr_reader :column, :config, :table
|
|
7
7
|
|
|
8
|
+
config_reader :operator
|
|
9
|
+
config_reader :value
|
|
8
10
|
config_reader :scope
|
|
9
11
|
|
|
10
|
-
def initialize(
|
|
11
|
-
@value = value
|
|
12
|
+
def initialize(column:, config:, table:)
|
|
12
13
|
@column = column
|
|
13
|
-
@config = config
|
|
14
|
+
@config = self.class.definition.merge(config || {})
|
|
14
15
|
@table = table
|
|
15
16
|
end
|
|
16
17
|
|
|
@@ -27,5 +28,33 @@ module Mensa
|
|
|
27
28
|
def to_s
|
|
28
29
|
"#{column.human_name}: #{value}"
|
|
29
30
|
end
|
|
31
|
+
|
|
32
|
+
def filter_scope(to_be_filtered_scope)
|
|
33
|
+
if scope
|
|
34
|
+
to_be_filtered_scope.instance_exec(normalize(value), &scope)
|
|
35
|
+
else
|
|
36
|
+
case operator
|
|
37
|
+
when :matches
|
|
38
|
+
to_be_filtered_scope.where("#{column.attribute_for_condition} LIKE ?", "%#{normalize(value)}%")
|
|
39
|
+
when :equals
|
|
40
|
+
to_be_filtered_scope.where(column.attribute_for_condition => normalize(value))
|
|
41
|
+
else
|
|
42
|
+
# Ignore unknown operators
|
|
43
|
+
to_be_filtered_scope
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
class << self
|
|
51
|
+
def definition(&)
|
|
52
|
+
@definition ||= Mensa::Config::FilterDsl.new(self.name, &).config
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def normalize(query)
|
|
57
|
+
query.to_s.gsub(/\s(?![\&\!\|])/, '\\\\ ')
|
|
58
|
+
end
|
|
30
59
|
end
|
|
31
60
|
end
|
data/app/tables/mensa/scope.rb
CHANGED
|
@@ -22,16 +22,9 @@ module Mensa
|
|
|
22
22
|
# This has problems - not all table fields are searched
|
|
23
23
|
@filtered_scope = @filtered_scope.basic_search(params[:query]) if params[:query]
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@filtered_scope = if column.filter&.scope
|
|
30
|
-
@filtered_scope.instance_exec(Helper.normalize(value), &column.filter.scope)
|
|
31
|
-
else
|
|
32
|
-
@filtered_scope.where(column.attribute_for_condition => Helper.normalize(value))
|
|
33
|
-
end
|
|
34
|
-
end
|
|
25
|
+
# Use inject
|
|
26
|
+
active_filters.each do |filter|
|
|
27
|
+
@filtered_scope = filter.filter_scope(@filtered_scope)
|
|
35
28
|
end
|
|
36
29
|
|
|
37
30
|
@filtered_scope
|
|
@@ -81,13 +74,5 @@ module Mensa
|
|
|
81
74
|
.reject { |name, direction| direction.blank? }
|
|
82
75
|
.transform_values { |value| value.to_sym }
|
|
83
76
|
end
|
|
84
|
-
|
|
85
|
-
module Helper
|
|
86
|
-
class << self
|
|
87
|
-
def normalize(query)
|
|
88
|
-
query.to_s.gsub(/\s(?![\&\!\|])/, '\\\\ ')
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
77
|
end
|
|
93
78
|
end
|
data/lib/mensa/version.rb
CHANGED
data/mensa.gemspec
CHANGED
|
@@ -34,9 +34,12 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.add_dependency 'pagy', '>=43'
|
|
35
35
|
spec.add_dependency 'textacular', '>=5'
|
|
36
36
|
|
|
37
|
+
|
|
37
38
|
spec.add_dependency 'slim'
|
|
38
39
|
spec.add_dependency 'tailwindcss-rails', "~> 3.3"
|
|
39
40
|
spec.add_dependency 'importmap-rails'
|
|
40
41
|
spec.add_dependency 'turbo-rails'
|
|
41
42
|
spec.add_dependency 'stimulus-rails'
|
|
43
|
+
|
|
44
|
+
spec.add_development_dependency "sqlite3", "~> 2.8"
|
|
42
45
|
end
|
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.2.
|
|
4
|
+
version: 0.2.2
|
|
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: 2025-11-
|
|
11
|
+
date: 2025-11-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: caxlsx_rails
|
|
@@ -136,6 +136,20 @@ dependencies:
|
|
|
136
136
|
- - ">="
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
138
|
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: sqlite3
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '2.8'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - "~>"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '2.8'
|
|
139
153
|
description: Fast and awesome tables, with pagination, sorting, filtering and custom
|
|
140
154
|
views.
|
|
141
155
|
email:
|
|
@@ -170,10 +184,11 @@ files:
|
|
|
170
184
|
- app/components/mensa/control_bar/component.css
|
|
171
185
|
- app/components/mensa/control_bar/component.html.slim
|
|
172
186
|
- app/components/mensa/control_bar/component.rb
|
|
173
|
-
- app/components/mensa/
|
|
174
|
-
- app/components/mensa/
|
|
175
|
-
- app/components/mensa/
|
|
176
|
-
- app/components/mensa/
|
|
187
|
+
- app/components/mensa/filter/component_controller.js
|
|
188
|
+
- app/components/mensa/filter_list/component.css
|
|
189
|
+
- app/components/mensa/filter_list/component.html.slim
|
|
190
|
+
- app/components/mensa/filter_list/component.rb
|
|
191
|
+
- app/components/mensa/filter_list/component_controller.js
|
|
177
192
|
- app/components/mensa/header/component.css
|
|
178
193
|
- app/components/mensa/header/component.html.slim
|
|
179
194
|
- app/components/mensa/header/component.rb
|
|
File without changes
|