mensa 0.6.10 → 0.6.11

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: 14b28a5dcb74e6d3bfccaa9180f0ba2299b1c5bff0adc6e9bbd2a17ff2d91c19
4
- data.tar.gz: 552b80421e290566218fe4e7e495785f7208ffa8f397fd88859b4e4ad20d6a21
3
+ metadata.gz: 595e1c13d2966b2cf3991e4f145bf408655431ca50a388d47c5fc8532d534635
4
+ data.tar.gz: 06a44600cbf0f6cdf14f0cdc8dfd3e4cb31ca0749b0cfbbb9017295bcea6ec9a
5
5
  SHA512:
6
- metadata.gz: 4848da1b5f33354d6dc79a8b6f76ed68e43744706ce34b808910186de399ae19d49e85409a561d11d74376c3a067f411697432664d2274c28a869e83136fdde9
7
- data.tar.gz: 400e3c6400043dea964f3958a27704ae1b56dd7c475de8ba4f20a16b3b3b4682582e3229589d285b3f62377db326ff56b0ac17160544aa38369a11f6f4cc92ca
6
+ metadata.gz: 7873d0830a89a852aae065431b35312ab71d00284330bf6b20a7aacf64250f3480c28478955a86b6c5e90b2882be7d1de3d3df1ab3e0a8ee16e04834ddb9f258
7
+ data.tar.gz: f50ca9748a2fe082d257d79339f2408bd36dfca6bbd4dda32b184fefc5beee6570280eb1f289028d4c36ed7586a5cd6f56d80b87476992800621a68cdaa67adf
@@ -0,0 +1,34 @@
1
+ {
2
+ "features": {
3
+ "ghcr.io/devcontainers/features/common-utils:2": {
4
+ "version": "2.5.9",
5
+ "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:cb0c4d3c276f157eed17935747e364178d75fee17f55c4e129966f64633deb3a",
6
+ "integrity": "sha256:cb0c4d3c276f157eed17935747e364178d75fee17f55c4e129966f64633deb3a"
7
+ },
8
+ "ghcr.io/devcontainers/features/docker-in-docker:2": {
9
+ "version": "2.17.0",
10
+ "resolved": "ghcr.io/devcontainers/features/docker-in-docker@sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c",
11
+ "integrity": "sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c"
12
+ },
13
+ "ghcr.io/devcontainers/features/github-cli:1": {
14
+ "version": "1.1.0",
15
+ "resolved": "ghcr.io/devcontainers/features/github-cli@sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671",
16
+ "integrity": "sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671"
17
+ },
18
+ "ghcr.io/devcontainers/features/node:2": {
19
+ "version": "2.1.0",
20
+ "resolved": "ghcr.io/devcontainers/features/node@sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857",
21
+ "integrity": "sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857"
22
+ },
23
+ "ghcr.io/rails/devcontainer/features/activestorage": {
24
+ "version": "1.1.1",
25
+ "resolved": "ghcr.io/rails/devcontainer/features/activestorage@sha256:7fa8fff898ac33076ebf65631d3c6c902dc9bad87de3e5dfa645f3e2d7a35c07",
26
+ "integrity": "sha256:7fa8fff898ac33076ebf65631d3c6c902dc9bad87de3e5dfa645f3e2d7a35c07"
27
+ },
28
+ "ghcr.io/rails/devcontainer/features/postgres-client": {
29
+ "version": "1.2.0",
30
+ "resolved": "ghcr.io/rails/devcontainer/features/postgres-client@sha256:7e6b118646d6e0d82a9ec06e81ad1b5406f7042f0279d35fff3a7a612be7a050",
31
+ "integrity": "sha256:7e6b118646d6e0d82a9ec06e81ad1b5406f7042f0279d35fff3a7a612be7a050"
32
+ }
33
+ }
34
+ }
@@ -1,37 +1,34 @@
1
1
  // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
- // README at: https://github.com/devcontainers/templates/tree/main/src/ruby
2
+ // README at: https://github.com/devcontainers/templates/tree/main/src/ruby-rails-postgres
3
3
  {
4
4
  "name": "mensa",
5
- "dockerComposeFile": "compose.yaml",
5
+ "dockerComposeFile": "docker-compose.yml",
6
6
  "service": "app",
7
- "workspaceFolder": "/workspaces/mensa",
8
- // Features to add to the dev container. More info: https://containers.dev/features.
9
7
  "features": {
10
- "ghcr.io/devcontainers/features/github-cli:1": {},
8
+ "ghcr.io/devcontainers/features/node:2": {},
9
+ "ghcr.io/devcontainers/features/common-utils:2": {
10
+ "configureZshAsDefaultShell": true,
11
+ "installOhMyZsh": false,
12
+ "installOhMyZshConfig": false
13
+ },
11
14
  "ghcr.io/rails/devcontainer/features/activestorage": {},
12
15
  "ghcr.io/rails/devcontainer/features/postgres-client": {
13
- "version": "17"
16
+ "version": "18"
14
17
  },
15
- "ghcr.io/devcontainers/features/node:1": {},
16
- "ghcr.io/duduribeiro/devcontainer-features/tmux:1": {}
18
+ "ghcr.io/devcontainers/features/github-cli:1": {},
19
+ "ghcr.io/devcontainers/features/docker-in-docker:2": {
20
+ "moby": false
21
+ }
17
22
  },
18
23
  "mounts": [
19
- "source=/run/host-services/ssh-auth.sock,target=/ssh-agent,type=bind",
24
+ "source=/run/host-services/ssh-auth.sock,target=/ssh-agent,type=bind,consistency=cached",
20
25
  "source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached"
21
26
  ],
22
- "postCreateCommand": ".devcontainer/postCreate.sh",
23
27
  "postStartCommand": ".devcontainer/postStart.sh",
24
28
  "containerEnv": {
25
- "CAPYBARA_SERVER_PORT": "45678",
26
- "SELENIUM_URL": "http://host.docker.internal:4444/",
27
29
  "VISUAL": "vi",
28
- "DB_HOST": "postgres",
29
30
  "SSH_AUTH_SOCK": "/ssh-agent"
30
31
  },
31
- "build": {
32
- "args": {
33
- "RUBY_VERSION": "3.4.7"
34
- },
35
- "dockerfile": "./devcontainer/Dockerfile"
36
- }
32
+ "customizations": {},
33
+ "workspaceFolder": "/workspaces/mensa"
37
34
  }
@@ -0,0 +1,35 @@
1
+ name: mensa
2
+
3
+ services:
4
+ app:
5
+ image: ghcr.io/rails/devcontainer/images/ruby:4.0.5
6
+
7
+ volumes:
8
+ - ../..:/workspaces
9
+
10
+ # Overrides default command so things don't shut down after the process ends.
11
+ command: sleep infinity
12
+
13
+ depends_on:
14
+ - postgres
15
+ - redis
16
+
17
+ postgres:
18
+ image: postgres:18
19
+ restart: unless-stopped
20
+ volumes:
21
+ - postgres-data:/var/lib/postgresql/18/docker
22
+ environment:
23
+ POSTGRES_USER: postgres
24
+ POSTGRES_PASSWORD: postgres
25
+
26
+ redis:
27
+ image: valkey/valkey:8
28
+ restart: unless-stopped
29
+
30
+ selenium:
31
+ image: selenium/standalone-firefox
32
+ restart: unless-stopped
33
+
34
+ volumes:
35
+ postgres-data:
@@ -1,9 +1,13 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- MISE=$(which mise)
5
- eval "$($MISE activate bash)"
4
+ MISE="$HOME/.local/bin/mise"
5
+ eval "$("$MISE" activate bash)"
6
+ "$MISE" trust
7
+ "$MISE" install
8
+ sudo chmod 666 /ssh-agent
6
9
 
7
- npm install
8
- bundle install
9
- rake db:prepare
10
+ "$MISE" exec -- npm install
11
+ "$MISE" exec -- bundle install
12
+ "$MISE" exec --cd test/dummy -- rake db:prepare
13
+ "$MISE" exec --cd test/dummy -- rake tailwindcss:config
data/.prettierrc.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "semi": false
3
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "i18n-ally-next.localesPaths": [
3
+ "config/locales/**"
4
+ ],
5
+ "i18n-ally-next.displayLanguage": "nl",
6
+ "i18n-ally-next.annotationMaxLength": 60,
7
+ "i18n-ally-next.keystyle": "nested",
8
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
3
+ // for the documentation about the tasks.json format
4
+ "version": "2.0.0",
5
+ "tasks": [
6
+ {
7
+ "label": "server",
8
+ "type": "shell",
9
+ "command": "if [ -f tmp/pids/server.pid ]; then pid=$(cat tmp/pids/server.pid); kill \"$pid\" 2>/dev/null || true; rm -f tmp/pids/server.pid; fi; mise exec -- bin/rails server -p 3000 -b 0.0.0.0",
10
+ "presentation": {
11
+ "reveal": "always",
12
+ "panel": "new"
13
+ },
14
+ "isBackground": true,
15
+ "problemMatcher": [],
16
+ "icon": {
17
+ "id": "server"
18
+ }
19
+ },
20
+ {
21
+ "label": "css",
22
+ "type": "shell",
23
+ "command": "cd test/dummy && mise exec -- bin/rails tailwindcss:config && mise exec -- bin/rails tailwindcss:watch",
24
+ "presentation": {
25
+ "reveal": "always",
26
+ "panel": "new"
27
+ },
28
+ "isBackground": true,
29
+ "problemMatcher": [],
30
+ "icon": {
31
+ "id": "json"
32
+ }
33
+ },
34
+ {
35
+ "label": "start all",
36
+ "dependsOn": [
37
+ "server",
38
+ "css"
39
+ ],
40
+ "problemMatcher": [],
41
+ "presentation": {
42
+ "reveal": "always",
43
+ "panel": "new"
44
+ }
45
+ }
46
+ ]
47
+ }
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mensa (0.6.9)
4
+ mensa (0.6.10)
5
5
  csv
6
6
  importmap-rails
7
7
  pagy (>= 43)
@@ -2,7 +2,7 @@
2
2
  <% if column.sortable? %>
3
3
  <%= link_to table.path(order: {column.name => column.next_sort_direction}, turbo_frame_id: table.table_id), "data-turbo-frame": "_self", class: "order cursor-pointer" do %>
4
4
  <span><%= column.human_name %></span>
5
- <i class="<%= Mensa.config.icons["header_order_indicator#{column.sort_direction.to_s.present? ? "_#{column.sort_direction}" : ""}".to_sym] %>"></i>
5
+ <i class="<%= Mensa.config.icons[column.sort_indicator_icon_key.to_sym] %>"></i>
6
6
  <% end %>
7
7
  <% else %>
8
8
  <div class="container">
@@ -1,44 +1,44 @@
1
1
  .mensa-table {
2
- .paging {
3
- @apply flex items-center justify-between border-t border-gray-100 dark:border-gray-700 bg-white dark:bg-gray-800 px-4 py-3 sm:px-6 text-sm;
4
-
5
- .pagy {
6
- @apply isolate inline-flex -space-x-px text-gray-500 dark:text-gray-400;
7
-
8
- a:not(.gap) {
9
- @apply relative inline-flex items-center px-4 py-1.5 text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 focus:z-20 no-underline;
10
-
11
- &:first-child {
12
- border-top-left-radius: 4px;
13
- border-bottom-left-radius: 4px;
14
- }
15
-
16
- &:last-child {
17
- border-top-right-radius: 4px;
18
- border-bottom-right-radius: 4px;
19
- }
20
-
21
- &:hover {
22
- @apply bg-gray-300 dark:bg-gray-600;
23
- }
24
-
25
- &:not([href]) {
26
- /* disabled links */
27
- @apply bg-gray-100 dark:bg-gray-800 hover:bg-gray-100 hover:dark:bg-gray-800 text-gray-700 dark:text-gray-100 text-opacity-25 dark:text-opacity-50 cursor-default;
28
- }
29
-
30
- &.current {
31
- @apply z-10 bg-primary-200 dark:bg-primary-800 hover:bg-primary-200 hover:dark:bg-primary-400 text-opacity-75 dark:text-opacity-75 border-none;
32
- }
33
- }
34
-
35
- label {
36
- @apply inline-block whitespace-nowrap bg-gray-200 dark:bg-gray-600 rounded-lg px-4 py-1.5;
37
-
38
- input {
39
- @apply bg-gray-100 dark:bg-gray-700 border-none rounded-md;
2
+ .paging {
3
+ @apply flex items-center justify-between border-t border-gray-100 dark:border-gray-700 bg-white dark:bg-gray-800 px-4 py-3 sm:px-6 text-sm;
4
+
5
+ .pagy {
6
+ @apply isolate inline-flex -space-x-px text-gray-500 dark:text-gray-400;
7
+
8
+ a:not(.gap) {
9
+ @apply relative inline-flex items-center px-4 py-1.5 text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 focus:z-20 no-underline;
10
+
11
+ &:first-child {
12
+ border-top-left-radius: 4px;
13
+ border-bottom-left-radius: 4px;
14
+ }
15
+
16
+ &:last-child {
17
+ border-top-right-radius: 4px;
18
+ border-bottom-right-radius: 4px;
19
+ }
20
+
21
+ &:hover {
22
+ @apply bg-gray-300 dark:bg-gray-600;
23
+ }
24
+
25
+ &:not([href]) {
26
+ /* disabled links */
27
+ @apply bg-gray-100 dark:bg-gray-800 hover:bg-gray-100 hover:dark:bg-gray-800 text-gray-700 dark:text-gray-100 text-opacity-25 dark:text-opacity-50 cursor-default;
28
+ }
29
+
30
+ &[aria-current="page"] {
31
+ @apply z-10 bg-primary-200 dark:bg-primary-800 hover:bg-primary-200 hover:dark:bg-primary-800 text-gray-900 dark:text-white text-opacity-100 dark:text-opacity-100 border-none font-semibold;
32
+ }
33
+ }
34
+
35
+ label {
36
+ @apply inline-block whitespace-nowrap bg-gray-200 dark:bg-gray-600 rounded-lg px-4 py-1.5;
37
+
38
+ input {
39
+ @apply bg-gray-100 dark:bg-gray-700 border-none rounded-md;
40
+ }
41
+ }
40
42
  }
41
- }
42
43
  }
43
- }
44
44
  }
@@ -200,6 +200,22 @@ module Mensa
200
200
  config[:turbo_frame_id]
201
201
  end
202
202
 
203
+ # Minimal state needed to reconstruct this table on another page (for
204
+ # next_record/previous_record navigation).
205
+ def navigation_context
206
+ context = {}
207
+
208
+ context[:params] = params if params.present?
209
+ context[:query] = current_query if config.key?(:query) && !current_query.nil?
210
+ context[:order] = current_order if current_order.present?
211
+ context[:filters] = config[:filters] if config[:filters].present?
212
+ context[:table_view_id] = current_table_view_id if config.key?(:table_view_id) && !current_table_view_id.nil?
213
+ context[:column_order] = current_column_order if config.key?(:column_order) && !current_column_order.nil?
214
+ context[:hidden_columns] = current_hidden_columns if config.key?(:hidden_columns) && !current_hidden_columns.nil?
215
+
216
+ context
217
+ end
218
+
203
219
  private
204
220
 
205
221
  def ensure_internal_columns_for_joined_associations
@@ -100,5 +100,27 @@ module Mensa
100
100
  name.to_s.humanize
101
101
  end
102
102
  end
103
+
104
+ # Determines the sort indicator icon key based on column type
105
+ def sort_indicator_icon_key
106
+ numeric_types = [:integer, :decimal, :float, :bigint]
107
+ date_types = [:date, :datetime, :time, :timestamp]
108
+ text_types = [:string, :text]
109
+
110
+ column_type = type
111
+ direction = sort_direction.to_s.presence || ""
112
+ direction_suffix = direction.present? ? "_#{direction}" : ""
113
+
114
+ case column_type
115
+ when *numeric_types
116
+ "header_order_indicator_numeric#{direction_suffix}"
117
+ when *date_types
118
+ "header_order_indicator_date#{direction_suffix}"
119
+ when *text_types
120
+ "header_order_indicator_text#{direction_suffix}"
121
+ else
122
+ "header_order_indicator#{direction_suffix}"
123
+ end
124
+ end
103
125
  end
104
126
  end
@@ -25,6 +25,7 @@ module Mensa
25
25
  [:gteq, I18n.t("mensa.operators.gteq"), true],
26
26
  [:lt, I18n.t("mensa.operators.lt"), true],
27
27
  [:lteq, I18n.t("mensa.operators.lteq"), true],
28
+ [:is_duplicate, I18n.t("mensa.operators.is_duplicate"), false],
28
29
  [:is_current, I18n.t("mensa.operators.is_current"), false],
29
30
  [:is_empty, I18n.t("mensa.operators.is_empty"), false],
30
31
  [:isnt_empty, I18n.t("mensa.operators.isnt_empty"), false]
@@ -36,6 +37,7 @@ module Mensa
36
37
  @column = column
37
38
  @config = self.class.definition.merge(config || {})
38
39
  @table = table
40
+ validate_operators!
39
41
  end
40
42
 
41
43
  def multiple?
@@ -80,6 +82,8 @@ module Mensa
80
82
  if scope
81
83
  record_scope.instance_exec(normalize(value), &scope)
82
84
  else
85
+ return apply_duplicate_filter(record_scope) if operator == :is_duplicate
86
+
83
87
  query, hash = query_and_hash_for_operator
84
88
  record_scope = (column.filter.having? ? record_scope.having(query, hash) : record_scope.where(query, hash)) if query.present?
85
89
  record_scope
@@ -130,8 +134,7 @@ module Mensa
130
134
  when :lteq
131
135
  ":column <= :value"
132
136
  else
133
- # Ignore unknown operators
134
- nil
137
+ raise ArgumentError, "Unknown filter operator #{operator.inspect} for column :#{column.name}"
135
138
  end
136
139
  [query, hash]
137
140
  end
@@ -159,6 +162,23 @@ module Mensa
159
162
 
160
163
  private
161
164
 
165
+ def validate_operators!
166
+ valid_keys = Mensa::Filter.OPERATORS.map(&:first)
167
+
168
+ op = @config[:operator]
169
+ if op.present? && valid_keys.exclude?(op.to_sym)
170
+ raise ArgumentError, "Unknown filter operator #{op.inspect} configured for column :#{column.name}. " \
171
+ "Valid operators are: #{valid_keys.join(", ")}"
172
+ end
173
+
174
+ allowed_ops = Array(@config[:operators])
175
+ invalid = allowed_ops.map(&:to_sym) - valid_keys
176
+ if invalid.any?
177
+ raise ArgumentError, "Unknown filter operator(s) #{invalid.map(&:inspect).join(", ")} configured for column :#{column.name}. " \
178
+ "Valid operators are: #{valid_keys.join(", ")}"
179
+ end
180
+ end
181
+
162
182
  def label_for_value(selected_value, options)
163
183
  option = options.find { |_label, value| value.to_s == selected_value.to_s }
164
184
  option ? option.first : selected_value
@@ -173,6 +193,21 @@ module Mensa
173
193
  end
174
194
  end
175
195
 
196
+ def apply_duplicate_filter(record_scope)
197
+ column_sql = column.attribute_for_condition.to_s
198
+ base_scope = record_scope.except(:select, :order, :limit, :offset)
199
+
200
+ duplicate_values_scope = base_scope
201
+ .where("#{column_sql} IS NOT NULL")
202
+ .group(column_sql)
203
+ .having("COUNT(*) > 1")
204
+ .select(Arel.sql(column_sql))
205
+
206
+ record_scope
207
+ .where("#{column_sql} IS NOT NULL")
208
+ .where("#{column_sql} IN (#{duplicate_values_scope.to_sql})")
209
+ end
210
+
176
211
  # Unused at the moment
177
212
  def normalize(query)
178
213
  query
@@ -30,7 +30,24 @@ module Mensa
30
30
  end
31
31
 
32
32
  def link
33
- table.original_view_context.instance_exec(record, &table.link) if table.link
33
+ return unless table.link
34
+
35
+ append_navigation_context(table.original_view_context.instance_exec(record, &table.link))
36
+ end
37
+
38
+ private
39
+
40
+ def append_navigation_context(url)
41
+ return url if url.blank?
42
+
43
+ uri = URI.parse(url)
44
+ existing_query = Rack::Utils.parse_nested_query(uri.query)
45
+ merged_query = table.navigation_context.deep_stringify_keys.deep_merge(existing_query)
46
+ query_string = merged_query.to_query
47
+ uri.query = query_string.presence
48
+ uri.to_s
49
+ rescue URI::InvalidURIError
50
+ url
34
51
  end
35
52
  end
36
53
  end
@@ -62,8 +62,41 @@ module Mensa
62
62
  @pagy_details
63
63
  end
64
64
 
65
+ # Returns the next record in the fully filtered/ordered result set.
66
+ # Pagination is intentionally ignored.
67
+ def next_record(record)
68
+ adjacent_record(record, step: 1)
69
+ end
70
+
71
+ # Returns the previous record in the fully filtered/ordered result set.
72
+ # Pagination is intentionally ignored.
73
+ def previous_record(record)
74
+ adjacent_record(record, step: -1)
75
+ end
76
+
65
77
  private
66
78
 
79
+ def adjacent_record(record, step:)
80
+ records = ordered_scope.to_a
81
+ index = records.find_index { |candidate| same_record?(candidate, record) }
82
+ return if index.nil?
83
+
84
+ adjacent_index = index + step
85
+ return if adjacent_index.negative? || adjacent_index >= records.length
86
+
87
+ records[adjacent_index]
88
+ end
89
+
90
+ def same_record?(left, right)
91
+ return false if left.nil? || right.nil?
92
+
93
+ if left.respond_to?(:id) && right.respond_to?(:id)
94
+ left.id == right.id
95
+ else
96
+ left == right
97
+ end
98
+ end
99
+
67
100
  def pagy_object
68
101
  return if @pagy_details && @records
69
102
 
@@ -76,7 +109,10 @@ module Mensa
76
109
  def effective_order
77
110
  result = current_order_provided? ? (current_order || {}) : (config[:order] || {})
78
111
  result = result.symbolize_keys.compact_blank.transform_values(&:to_sym)
79
- result.map { |k,v| "#{k} #{v} NULLS LAST" }.join(", ")
112
+ result.filter_map { |k, v|
113
+ attribute = column(k)&.attribute_for_condition || k
114
+ "#{attribute} #{v} NULLS LAST"
115
+ }.join(", ")
80
116
  end
81
117
 
82
118
  # Builds an order hash for URL generation. Merges current order with overrides;
@@ -20,6 +20,7 @@ en:
20
20
  lt: less than
21
21
  gteq: greater than or equal to
22
22
  lteq: less than or equal to
23
+ is_duplicate: is duplicate
23
24
  is_empty: is empty
24
25
  isnt_empty: is not empty
25
26
  add_filter:
@@ -20,6 +20,7 @@ nl:
20
20
  lt: kleiner dan
21
21
  gteq: groter dan of gelijk aan
22
22
  lteq: kleiner dan of gelijk aan
23
+ is_duplicate: is dubbel
23
24
  is_empty: is leeg
24
25
  isnt_empty: is niet leeg
25
26
  add_filter:
@@ -26,6 +26,12 @@ Mensa.setup do |config|
26
26
  filter_pill_list_clear: "fa-solid fa-xmark",
27
27
  header_order_indicator_asc: "fa-solid fa-arrow-up",
28
28
  header_order_indicator_desc: "fa-solid fa-arrow-down",
29
+ header_order_indicator_numeric_asc: "fa-solid fa-arrow-down-1-9",
30
+ header_order_indicator_numeric_desc: "fa-solid fa-arrow-down-9-1",
31
+ header_order_indicator_date_asc: "fa-solid fa-arrow-down-1-9",
32
+ header_order_indicator_date_desc: "fa-solid fa-arrow-down-9-1",
33
+ header_order_indicator_text_asc: "fa-solid fa-arrow-down-a-z",
34
+ header_order_indicator_text_desc: "fa-solid fa-arrow-down-z-a",
29
35
  action_column_header: "fa-solid fa-ellipsis",
30
36
  views_trigger: "fa-solid fa-sort",
31
37
  views_option_selected: "fa-solid fa-check",
@@ -59,6 +59,12 @@ module Mensa
59
59
  filter_pill_list_clear: "fa-solid fa-xmark",
60
60
  header_order_indicator_asc: "fa-solid fa-sm fa-arrow-up",
61
61
  header_order_indicator_desc: "fa-solid fa-sm fa-arrow-down",
62
+ header_order_indicator_numeric_asc: "fa-solid fa-sm fa-arrow-down-1-9",
63
+ header_order_indicator_numeric_desc: "fa-solid fa-sm fa-arrow-down-9-1",
64
+ header_order_indicator_date_asc: "fa-solid fa-sm fa-arrow-down-1-9",
65
+ header_order_indicator_date_desc: "fa-solid fa-sm fa-arrow-down-9-1",
66
+ header_order_indicator_text_asc: "fa-solid fa-sm fa-arrow-down-a-z",
67
+ header_order_indicator_text_desc: "fa-solid fa-sm fa-arrow-down-z-a",
62
68
  action_column_header: "fa-solid fa-ellipsis",
63
69
  views_trigger: "fa-solid fa-sort",
64
70
  views_option_selected: "fa-solid fa-check",
data/lib/mensa/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mensa
2
- VERSION = "0.6.10"
2
+ VERSION = "0.6.11"
3
3
  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.6.10
4
+ version: 0.6.11
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-06-18 00:00:00.000000000 Z
11
+ date: 2026-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -159,14 +159,17 @@ extensions: []
159
159
  extra_rdoc_files: []
160
160
  files:
161
161
  - ".devcontainer/Dockerfile"
162
- - ".devcontainer/compose.yaml"
162
+ - ".devcontainer/devcontainer-lock.json"
163
163
  - ".devcontainer/devcontainer.json"
164
- - ".devcontainer/postCreate.sh"
164
+ - ".devcontainer/docker-compose.yml"
165
165
  - ".devcontainer/postStart.sh"
166
166
  - ".gem_release.yml"
167
167
  - ".github/workflows/gem-push.yml"
168
168
  - ".gitignore"
169
+ - ".prettierrc.json"
169
170
  - ".rubocop.yml"
171
+ - ".vscode/settings.json"
172
+ - ".vscode/tasks.json"
170
173
  - ".zed/tasks.json"
171
174
  - CHANGELOG.md
172
175
  - Gemfile
@@ -1,49 +0,0 @@
1
- name: "mensa"
2
-
3
- services:
4
- app:
5
- cpu_count: 2
6
- build:
7
- context: ..
8
- dockerfile: .devcontainer/Dockerfile
9
-
10
- volumes:
11
- - ../..:/workspaces:cached
12
- # Overrides default command so things don't shut down after the process ends.
13
- command: sleep infinity
14
-
15
- # Uncomment the next line to use a non-root user for all processes.
16
- # user: vscode
17
-
18
- # Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
19
- # (Adding the "ports" property to this file will not forward from a Codespace.)
20
- depends_on:
21
- - selenium
22
- - postgres
23
- - redis
24
-
25
- environment:
26
- - DATABASE_URL=postgres://postgres:postgres@postgres:5432
27
- - RUBY_YJIT_ENABLE=1
28
-
29
- selenium:
30
- image: selenium/standalone-firefox
31
- restart: unless-stopped
32
-
33
- redis:
34
- image: redis:6.2
35
- restart: unless-stopped
36
-
37
- postgres:
38
- image: postgres:17.0
39
- restart: unless-stopped
40
- networks:
41
- - default
42
- volumes:
43
- - postgres-data:/var/lib/postgresql/data
44
- environment:
45
- POSTGRES_USER: postgres
46
- POSTGRES_PASSWORD: postgres
47
-
48
- volumes:
49
- postgres-data:
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -e
3
- MISE=$(which mise)
4
-
5
- eval "$($MISE activate bash)"
6
- $MISE trust
7
- $MISE install
8
- sudo chmod 666 /ssh-agent