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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bcf63a1e05c2caa2ec8ef66f7ce73b721f5d6a895902aaa7f800ad8957b824b6
4
- data.tar.gz: 9ea3064bbcf09518f0eee1709dac74e39150873a02d3ef48cc063ae68b46d631
3
+ metadata.gz: e79f4a4d3a4be038ed02e0f7dd30fee1abf0b6945b1a5817f05103928c288296
4
+ data.tar.gz: 888bdc7e9aeead37ec6f0461b7bcedd4a63905eaad8a75a4f57b698c88d8a05f
5
5
  SHA512:
6
- metadata.gz: fe1630a7ce720705a3c58803eb376727cfebc794f68c404b3d07a757041e25bc39dcd40781a32548af79e3c2d7ac1485e28d0158ec4741cd9c76b13f3ecb8c20
7
- data.tar.gz: a69e2ac944ee88bd3e434f0e4b5271bc7f9c10d73c6e16c526c37f0d774d379f435a49d953ea40ad38f7b5aa864a2437364dd2b5ea48ffb048f13ade524e71b7
6
+ metadata.gz: 2b8d4acf77c6ed877a58ad145cd522fa50fccf770336f13e657c312c7d04a2a1e0b9eb37c9d6d7a16745c17924d3969deb6777921280834e31fa4a45cd29d644
7
+ data.tar.gz: b8053f1def913871788a7f3e2530e4ff7946e241af8c258d1a392b637aabad9bc3c40eaa0b71ab34c7454d2b1091346e2683b1a93e1f299af11845e28aecc886
data/Gemfile CHANGED
@@ -12,3 +12,4 @@ gem "pry"
12
12
  gem "capybara", "~> 3.40"
13
13
  gem "selenium-webdriver", "~> 4.17"
14
14
  gem "slim", "~> 5.2"
15
+ gem "debug"
data/Gemfile.lock CHANGED
@@ -17,7 +17,7 @@ GIT
17
17
  PATH
18
18
  remote: .
19
19
  specs:
20
- mensa (0.1.17)
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
- - [ ] filtering (of multiple columns, single is done)
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 (event) {
28
+ toggle(event) {
29
29
  this.filterListTarget.classList.toggle('hidden')
30
30
  }
31
31
 
32
32
  // Called when you selected a column
33
- openValuePopover (event) {
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 (event) {
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 (event) {
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.filtersTarget.addEventListener("turbo:after-stream-render", this.unhide.bind(this)) ?
80
+ // this.mensaTableOutlet.filterListTarget.addEventListener("turbo:after-stream-render", this.unhide.bind(this)) ?
77
81
  setTimeout(() => {
78
- this.mensaTableOutlet.filtersTarget.classList.remove('hidden')
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="filters"
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,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mensa
4
- module Filters
4
+ module FilterList
5
5
  class Component < ::Mensa::ApplicationComponent
6
6
  attr_reader :table
7
7
 
@@ -10,4 +10,4 @@ module Mensa
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -1,6 +1,6 @@
1
1
  import ApplicationController from 'mensa/controllers/application_controller'
2
2
 
3
- export default class FiltersComponentController extends ApplicationController {
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.name *action.link_attributes
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::Filters::Component.new(table: table)
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
- "filters", // Tabs or list of filters
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.filtersTarget.classList.remove("hidden");
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.filtersTarget.classList.remove("hidden");
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.filtersTarget.classList.add("hidden");
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.filtersTarget.classList.add("hidden");
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 FiltersComponentController from "mensa/components/filters/component_controller";
10
- application.register("mensa-filters", FiltersComponentController);
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);
@@ -18,9 +18,11 @@ module Mensa
18
18
  @config = config
19
19
  end
20
20
 
21
- config_reader :link
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
@@ -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, value| Mensa::Filter.new(value, column: column(column_name), config: config.dig(:filters, column_name), table: self) }
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
@@ -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(nil, column: self, config: config[:filter] || {}, table: table)
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: :true
20
- dsl_option :render, Mensa::Config::RenderDsl
21
- dsl_option :filter, Mensa::Config::FilterDsl
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 define_dsl :render, Mensa::RenderDsl
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
 
@@ -2,6 +2,8 @@ module Mensa::Config
2
2
  class FilterDsl
3
3
  include DslLogic
4
4
 
5
+ option :operator, default: :equals
6
+ option :value
5
7
  option :collection
6
8
  option :scope
7
9
  end
@@ -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
- dsl_option :render, Mensa::Config::RenderDsl
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
- def config_reader(name)
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
@@ -3,14 +3,15 @@
3
3
  module Mensa
4
4
  class Filter
5
5
  include ConfigReaders
6
- attr_reader :column, :value, :config, :table
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(value, column:, config:, table:)
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
@@ -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
- if params[:filters]
26
- params[:filters].each do |column_name, value|
27
- next unless (column = column(column_name))
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
@@ -1,5 +1,5 @@
1
1
  = turbo_stream.update "filters-#{@table.table_id}" do
2
- = render Mensa::Filters::Component.new(table: @table)
2
+ = render Mensa::FilterList::Component.new(table: @table)
3
3
 
4
4
  = turbo_stream.update @table.table_id do
5
5
  = render Mensa::View::Component.new(@table)
data/lib/mensa/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mensa
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.2"
3
3
  end
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.0
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-06 00:00:00.000000000 Z
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/filters/component.css
174
- - app/components/mensa/filters/component.html.slim
175
- - app/components/mensa/filters/component.rb
176
- - app/components/mensa/filters/component_controller.js
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