mensa 0.6.1 → 0.6.3
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.lock +1 -1
- data/app/components/mensa/control_bar/component.css +12 -0
- data/app/components/mensa/copyable/component_controller.js +32 -0
- data/app/components/mensa/header/component.css +7 -11
- data/app/components/mensa/view/component.css +19 -11
- data/app/components/mensa/view/component.html.erb +2 -2
- data/app/controllers/mensa/tables/exports_controller.rb +1 -1
- data/app/javascript/mensa/controllers/index.js +3 -0
- data/app/jobs/mensa/export_job.rb +52 -22
- data/app/tables/mensa/filter.rb +8 -1
- data/app/views/mensa/exports/_list.html.erb +9 -0
- data/config/locales/en.yml +1 -1
- data/config/locales/nl.yml +1 -1
- data/db/migrate/20260616113603_add_password_to_export.rb +5 -0
- data/lib/generators/mensa/templates/config/initializers/mensa.rb +1 -0
- data/lib/mensa/configuration.rb +5 -4
- data/lib/mensa/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b6c3d12b5f69c5a0893eae56ffda155d75a658dc46620aa18cbd379d0773e16e
|
|
4
|
+
data.tar.gz: 9e26900083f2aba091e70e5cbcc695f575432c0705b2cc6cda56df78b2d97ed3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c5edc68c51ba784fb05689a538fdeec88dccfaeadee54df43a10af537700b442eb16344848a60fa7b8da20ed4c4dde8754e3c2a9bad3848ba71ed255e2598f07
|
|
7
|
+
data.tar.gz: 327b344e58309db72a11b1d90c8d8eae950b92571434144c3f237e6aa4161ac5eb9221bb3d33609f883e1a38bd6a6c4f0eb5a11a564adf79890fe9f69083ae25
|
data/Gemfile.lock
CHANGED
|
@@ -89,6 +89,18 @@
|
|
|
89
89
|
@apply text-xs font-normal text-gray-400 dark:text-gray-500;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
&__item-password {
|
|
93
|
+
@apply inline-flex items-center gap-1 text-xs text-gray-500 dark:text-gray-400;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&__item-password-value {
|
|
97
|
+
@apply rounded bg-gray-100 dark:bg-gray-700 px-1 py-0.5 font-mono text-[0.6875rem] text-gray-700 dark:text-gray-200;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
&__item-password-copy {
|
|
101
|
+
@apply inline-flex h-5 w-5 items-center justify-center rounded text-gray-400 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-gray-200 focus:outline-none focus:ring-2 focus:ring-gray-400 cursor-pointer;
|
|
102
|
+
}
|
|
103
|
+
|
|
92
104
|
&__download {
|
|
93
105
|
@apply inline-flex items-center gap-1.5 rounded-md bg-white dark:bg-gray-700 px-2.5 py-1.5 text-sm font-medium text-primary-600 dark:text-primary-300 ring-1 ring-inset ring-gray-300 dark:ring-gray-600 hover:bg-gray-50 dark:hover:bg-gray-600;
|
|
94
106
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import ApplicationController from "mensa/controllers/application_controller";
|
|
2
|
+
|
|
3
|
+
export default class CopyableComponentController extends ApplicationController {
|
|
4
|
+
static values = {
|
|
5
|
+
text: String,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
async copy(event) {
|
|
9
|
+
event.preventDefault();
|
|
10
|
+
|
|
11
|
+
if (!this.hasTextValue) return;
|
|
12
|
+
|
|
13
|
+
if (navigator.clipboard?.writeText) {
|
|
14
|
+
await navigator.clipboard.writeText(this.textValue);
|
|
15
|
+
} else {
|
|
16
|
+
this._copyWithFallback(this.textValue);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_copyWithFallback(text) {
|
|
21
|
+
const input = document.createElement("textarea");
|
|
22
|
+
input.value = text;
|
|
23
|
+
input.setAttribute("readonly", "");
|
|
24
|
+
input.style.position = "fixed";
|
|
25
|
+
input.style.top = "-9999px";
|
|
26
|
+
input.style.left = "-9999px";
|
|
27
|
+
document.body.appendChild(input);
|
|
28
|
+
input.select();
|
|
29
|
+
document.execCommand("copy");
|
|
30
|
+
input.remove();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
th {
|
|
7
|
-
@apply top-0 z-10 py-2 px-2 align-bottom text-left text-sm font-medium text-gray-500 border-b border-gray-200 dark:border-gray-600 whitespace-nowrap;
|
|
7
|
+
@apply top-0 z-10 py-1 pt-[7px] pb-2 px-2 align-bottom text-left text-sm font-medium text-gray-500 border-b border-gray-200 dark:border-gray-600 whitespace-nowrap;
|
|
8
8
|
|
|
9
9
|
&:first-child {
|
|
10
10
|
@apply pl-4;
|
|
@@ -15,20 +15,24 @@
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
.container {
|
|
18
|
-
@apply h-
|
|
18
|
+
@apply h-5 flex items-center;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
.title {
|
|
22
22
|
@apply w-full;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
&.actions {
|
|
26
|
+
@apply text-center;
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
/* For sortable columns the link takes over the cell's padding so
|
|
26
30
|
the entire th area — including what was padding — is clickable. */
|
|
27
31
|
&:has(.order) {
|
|
28
32
|
@apply p-0;
|
|
29
33
|
|
|
30
34
|
.order {
|
|
31
|
-
@apply flex items-center gap-1 w-full
|
|
35
|
+
@apply flex items-center gap-1 w-full pt-[7px] pb-2 px-2;
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
&:first-child .order {
|
|
@@ -41,12 +45,4 @@
|
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
|
-
|
|
45
|
-
&__column_edit {
|
|
46
|
-
thead {
|
|
47
|
-
th {
|
|
48
|
-
@apply cursor-grab;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
48
|
}
|
|
@@ -9,12 +9,10 @@
|
|
|
9
9
|
top: 0;
|
|
10
10
|
left: 0;
|
|
11
11
|
z-index: 10;
|
|
12
|
-
@apply pt-
|
|
12
|
+
@apply pt-[7px] pb-2 bg-gray-100 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600;
|
|
13
13
|
|
|
14
14
|
&__content {
|
|
15
|
-
|
|
16
|
-
pl-3 aligns the checkbox with the checkbox column (w-8, pl-4). */
|
|
17
|
-
@apply h-4 flex items-center gap-2 pl-4;
|
|
15
|
+
@apply h-5 flex items-center gap-2 pl-2;
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
&__count {
|
|
@@ -30,11 +28,15 @@
|
|
|
30
28
|
@apply bg-white dark:bg-gray-500 dark:border-gray-700;
|
|
31
29
|
|
|
32
30
|
.mensa-table__checkbox-col {
|
|
33
|
-
@apply w-
|
|
31
|
+
@apply w-7 min-w-7 pl-1 pr-0 text-center;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.mensa-table__checkbox-col .container {
|
|
35
|
+
@apply justify-center;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
.mensa-table__select-all {
|
|
37
|
-
@apply h-4 w-4 rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 cursor-pointer;
|
|
39
|
+
@apply inline-block h-4 w-4 rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 cursor-pointer;
|
|
38
40
|
appearance: none;
|
|
39
41
|
|
|
40
42
|
&:hover {
|
|
@@ -85,10 +87,6 @@
|
|
|
85
87
|
@apply bg-gray-100 top-0 dark:bg-gray-700 dark:font-medium dark:text-gray-400 dark:lowercase;
|
|
86
88
|
|
|
87
89
|
/* tr and th moved to header */
|
|
88
|
-
|
|
89
|
-
.mensa-table__checkbox-col {
|
|
90
|
-
@apply pr-2;
|
|
91
|
-
}
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
tbody {
|
|
@@ -99,7 +97,7 @@
|
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
td {
|
|
102
|
-
@apply px-2
|
|
100
|
+
@apply px-2 pt-[5px] pb-1.5 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400;
|
|
103
101
|
|
|
104
102
|
&:first-child {
|
|
105
103
|
@apply pl-4;
|
|
@@ -110,5 +108,15 @@
|
|
|
110
108
|
}
|
|
111
109
|
}
|
|
112
110
|
}
|
|
111
|
+
|
|
112
|
+
thead th.mensa-table__checkbox-col,
|
|
113
|
+
tbody td.mensa-table__checkbox-col {
|
|
114
|
+
@apply w-7 min-w-7 pl-1 pr-0 text-center;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
thead th.actions,
|
|
118
|
+
tbody td.actions {
|
|
119
|
+
@apply w-px whitespace-nowrap px-2 text-center;
|
|
120
|
+
}
|
|
113
121
|
}
|
|
114
122
|
}
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
</th>
|
|
28
28
|
<% end %>
|
|
29
29
|
<% if table.actions? && Mensa.config.row_actions_position == :front %>
|
|
30
|
-
<th
|
|
30
|
+
<th class="actions" aria-label="Actions"><i class="<%= Mensa.config.icons[:action_column_header] %>" aria-hidden="true"></i></th>
|
|
31
31
|
<% end %>
|
|
32
32
|
<%= render(Mensa::Header::Component.with_collection(table.display_columns, table: table)) %>
|
|
33
33
|
<% if table.actions? && Mensa.config.row_actions_position == :back %>
|
|
34
|
-
<th
|
|
34
|
+
<th class="actions" aria-label="Actions"><i class="<%= Mensa.config.icons[:action_column_header] %>" aria-hidden="true"></i></th>
|
|
35
35
|
<% end %>
|
|
36
36
|
</tr>
|
|
37
37
|
</thead>
|
|
@@ -30,6 +30,9 @@ application.register("mensa-selection", SelectionComponentController);
|
|
|
30
30
|
import ColumnCustomizerController from "mensa/components/column_customizer/component_controller";
|
|
31
31
|
application.register("mensa-column-customizer", ColumnCustomizerController);
|
|
32
32
|
|
|
33
|
+
import CopyableComponentController from "mensa/components/copyable/component_controller";
|
|
34
|
+
application.register("mensa-copyable", CopyableComponentController);
|
|
35
|
+
|
|
33
36
|
// Eager load all controllers defined in the import map under controllers/**/*_controller
|
|
34
37
|
// import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
|
|
35
38
|
// eagerLoadControllersFrom("controllers", application)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require "csv"
|
|
2
2
|
require "securerandom"
|
|
3
|
-
require "
|
|
3
|
+
require "tempfile"
|
|
4
4
|
|
|
5
5
|
module Mensa
|
|
6
6
|
# Generates the CSV for a Mensa::Export, attaches it to the export's +asset+
|
|
@@ -21,17 +21,19 @@ module Mensa
|
|
|
21
21
|
return
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
tempfile, filename, content_type = generate(table, export)
|
|
25
25
|
|
|
26
26
|
export.asset.purge if export.asset.attached?
|
|
27
|
-
export.asset.attach(io:
|
|
27
|
+
export.asset.attach(io: tempfile, filename: filename, content_type: content_type)
|
|
28
28
|
finalize(export, status: "completed", filename: filename)
|
|
29
29
|
|
|
30
30
|
Mensa.config.callbacks[:export_complete]&.call(export)
|
|
31
31
|
rescue => e
|
|
32
|
-
Mensa.config.logger&.error("Mensa::ExportJob failed for export #{
|
|
32
|
+
Mensa.config.logger&.error("Mensa::ExportJob failed for export #{export&.id}: #{e.class}: #{e.message}")
|
|
33
33
|
finalize(export, status: "failed") if export
|
|
34
34
|
raise
|
|
35
|
+
ensure
|
|
36
|
+
tempfile&.close!
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
private
|
|
@@ -56,35 +58,63 @@ module Mensa
|
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
def generate(table, export)
|
|
59
|
-
|
|
61
|
+
base_filename = "#{export.table_name}_export_#{export.created_at.strftime("%Y-%m-%d-%H%M%S")}"
|
|
62
|
+
csv_file = write_csv_file(table, export, base_filename)
|
|
63
|
+
|
|
64
|
+
if table.export_with_password?
|
|
65
|
+
zip_file = write_zip_file(csv_file, export, base_filename)
|
|
66
|
+
csv_file.close!
|
|
67
|
+
[zip_file, "#{base_filename}.zip", "application/zip"]
|
|
68
|
+
else
|
|
69
|
+
[csv_file, "#{base_filename}.csv", "text/csv"]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def write_csv_file(table, export, base_filename)
|
|
74
|
+
tempfile = Tempfile.new([base_filename, ".csv"], binmode: true)
|
|
75
|
+
|
|
60
76
|
# A UTF-8 BOM makes spreadsheet programs such as Excel detect the encoding
|
|
61
77
|
# correctly. The "plain" CSV variant omits it for maximum compatibility
|
|
62
78
|
# with programmatic consumers.
|
|
63
|
-
|
|
79
|
+
tempfile.write("\uFEFF") if export.format == "csv_excel"
|
|
64
80
|
|
|
65
|
-
csv = CSV.new(
|
|
81
|
+
csv = CSV.new(tempfile)
|
|
66
82
|
csv << table.display_columns.map(&:name)
|
|
67
83
|
export_rows(table, export).each do |row|
|
|
68
84
|
csv << table.display_columns.map { |column| Mensa::Cell.new(row: row, column: column).render(:csv) }
|
|
69
85
|
end
|
|
70
|
-
|
|
71
|
-
|
|
86
|
+
csv.close
|
|
87
|
+
tempfile.open
|
|
88
|
+
tempfile.binmode
|
|
89
|
+
tempfile.rewind
|
|
90
|
+
tempfile
|
|
91
|
+
rescue
|
|
92
|
+
tempfile&.close!
|
|
93
|
+
raise
|
|
94
|
+
end
|
|
72
95
|
|
|
73
|
-
|
|
96
|
+
def write_zip_file(csv_file, export, base_filename)
|
|
97
|
+
require "zip"
|
|
74
98
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
else
|
|
86
|
-
[data, "#{base_filename}.csv", "text/csv"]
|
|
99
|
+
zip_file = Tempfile.new([base_filename, ".zip"], binmode: true)
|
|
100
|
+
zip_path = zip_file.path
|
|
101
|
+
zip_file.close
|
|
102
|
+
|
|
103
|
+
export.password = SecureRandom.hex(6)
|
|
104
|
+
encrypter = Zip::TraditionalEncrypter.new(export.password)
|
|
105
|
+
Zip::OutputStream.open(zip_path, encrypter: encrypter) do |zio|
|
|
106
|
+
zio.put_next_entry("#{base_filename}.csv")
|
|
107
|
+
csv_file.rewind
|
|
108
|
+
IO.copy_stream(csv_file, zio)
|
|
87
109
|
end
|
|
110
|
+
|
|
111
|
+
zip_file.open
|
|
112
|
+
zip_file.binmode
|
|
113
|
+
zip_file.rewind
|
|
114
|
+
zip_file
|
|
115
|
+
rescue
|
|
116
|
+
zip_file&.close!
|
|
117
|
+
raise
|
|
88
118
|
end
|
|
89
119
|
|
|
90
120
|
def export_rows(table, export)
|
data/app/tables/mensa/filter.rb
CHANGED
|
@@ -25,7 +25,8 @@ module Mensa
|
|
|
25
25
|
[:lt, I18n.t("mensa.operators.lt"), true],
|
|
26
26
|
[:lteq, I18n.t("mensa.operators.lteq"), true],
|
|
27
27
|
[:is_current, I18n.t("mensa.operators.is_current"), false],
|
|
28
|
-
[:is_empty, I18n.t("mensa.operators.is_empty"), false]
|
|
28
|
+
[:is_empty, I18n.t("mensa.operators.is_empty"), false],
|
|
29
|
+
[:isnt_empty, I18n.t("mensa.operators.isnt_empty"), false]
|
|
29
30
|
].freeze
|
|
30
31
|
end
|
|
31
32
|
end
|
|
@@ -85,6 +86,12 @@ module Mensa
|
|
|
85
86
|
else
|
|
86
87
|
record_scope.where("#{column.attribute_for_condition} IS NULL")
|
|
87
88
|
end
|
|
89
|
+
when :isnt_empty
|
|
90
|
+
if column.type == :string
|
|
91
|
+
record_scope.where("#{column.attribute_for_condition} IS NOT NULL AND #{column.attribute_for_condition} != ''")
|
|
92
|
+
else
|
|
93
|
+
record_scope.where("#{column.attribute_for_condition} IS NOT NULL")
|
|
94
|
+
end
|
|
88
95
|
when :is_current
|
|
89
96
|
record_scope.where("#{column.attribute_for_condition} = ?", Current.send(column.name))
|
|
90
97
|
when :matches
|
|
@@ -19,6 +19,15 @@
|
|
|
19
19
|
<% if export.repeating? %>
|
|
20
20
|
<span class="mensa-table__export-dialog__item-repeat"><%= export.repeat_label %></span>
|
|
21
21
|
<% end %>
|
|
22
|
+
<% if export.password.present? %>
|
|
23
|
+
<span class="mensa-table__export-dialog__item-password" data-controller="mensa-copyable" data-mensa-copyable-text-value="<%= export.password %>">
|
|
24
|
+
<span class="mensa-table__export-dialog__item-password-label">Password:</span>
|
|
25
|
+
<code class="mensa-table__export-dialog__item-password-value"><%= export.password %></code>
|
|
26
|
+
<button class="mensa-table__export-dialog__item-password-copy" type="button" data-action="mensa-copyable#copy" aria-label="Copy password">
|
|
27
|
+
<i class="fas fa-copy" aria-hidden="true"></i>
|
|
28
|
+
</button>
|
|
29
|
+
</span>
|
|
30
|
+
<% end %>
|
|
22
31
|
<span class="mensa-table__export-dialog__item-meta"><%= export.created_at.strftime("%Y-%m-%d %H:%M") %></span>
|
|
23
32
|
</div>
|
|
24
33
|
<div class="mensa-table__export-dialog__item-action">
|
data/config/locales/en.yml
CHANGED
|
@@ -4,7 +4,6 @@ en:
|
|
|
4
4
|
filters:
|
|
5
5
|
show:
|
|
6
6
|
clear: Cancel
|
|
7
|
-
actions: Actions
|
|
8
7
|
save: Save
|
|
9
8
|
update_view: Update view
|
|
10
9
|
save_view: Save as new view
|
|
@@ -20,6 +19,7 @@ en:
|
|
|
20
19
|
gteq: greater than or equal to
|
|
21
20
|
lteq: less than or equal to
|
|
22
21
|
is_empty: is empty
|
|
22
|
+
isnt_empty: is not empty
|
|
23
23
|
add_filter:
|
|
24
24
|
add: Add filter
|
|
25
25
|
component:
|
data/config/locales/nl.yml
CHANGED
|
@@ -4,7 +4,6 @@ nl:
|
|
|
4
4
|
filters:
|
|
5
5
|
show:
|
|
6
6
|
clear: Annuleren
|
|
7
|
-
actions: Acties
|
|
8
7
|
save: Bewaar
|
|
9
8
|
update_view: Bewaar weergave
|
|
10
9
|
save_view: Bewaar als nieuwe weergave
|
|
@@ -20,6 +19,7 @@ nl:
|
|
|
20
19
|
gteq: groter dan of gelijk aan
|
|
21
20
|
lteq: kleiner dan of gelijk aan
|
|
22
21
|
is_empty: is leeg
|
|
22
|
+
isnt_empty: is niet leeg
|
|
23
23
|
add_filter:
|
|
24
24
|
add: Filter toevoegen
|
|
25
25
|
component:
|
|
@@ -26,6 +26,7 @@ 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
|
+
action_column_header: "fa-solid fa-ellipsis",
|
|
29
30
|
views_trigger: "fa-solid fa-sort",
|
|
30
31
|
views_option_selected: "fa-solid fa-check",
|
|
31
32
|
views_option_menu: "fa-solid fa-ellipsis",
|
data/lib/mensa/configuration.rb
CHANGED
|
@@ -57,8 +57,9 @@ module Mensa
|
|
|
57
57
|
filter_pill_remove: "fa-solid fa-xmark",
|
|
58
58
|
filter_pill_list_search: "fa-solid fa-magnifying-glass",
|
|
59
59
|
filter_pill_list_clear: "fa-solid fa-xmark",
|
|
60
|
-
header_order_indicator_asc: "fa-solid fa-arrow-up",
|
|
61
|
-
header_order_indicator_desc: "fa-solid fa-arrow-down",
|
|
60
|
+
header_order_indicator_asc: "fa-solid fa-sm fa-arrow-up",
|
|
61
|
+
header_order_indicator_desc: "fa-solid fa-sm fa-arrow-down",
|
|
62
|
+
action_column_header: "fa-solid fa-ellipsis",
|
|
62
63
|
views_trigger: "fa-solid fa-sort",
|
|
63
64
|
views_option_selected: "fa-solid fa-check",
|
|
64
65
|
views_option_menu: "fa-solid fa-ellipsis",
|
|
@@ -90,8 +91,8 @@ module Mensa
|
|
|
90
91
|
# filter_pill_remove: "fa-light fa-xmark",
|
|
91
92
|
# filter_pill_list_search: "fa-light fa-magnifying-glass",
|
|
92
93
|
# filter_pill_list_clear: "fa-light fa-xmark",
|
|
93
|
-
# header_order_indicator_asc: "fa-regular fa-arrow-up-short-wide",
|
|
94
|
-
# header_order_indicator_desc: "fa-regular fa-arrow-down-wide-short",
|
|
94
|
+
# header_order_indicator_asc: "fa-regular fa-sm fa-arrow-up-short-wide",
|
|
95
|
+
# header_order_indicator_desc: "fa-regular fa-sm fa-arrow-down-wide-short",
|
|
95
96
|
# views_trigger: "fa-light fa-sort",
|
|
96
97
|
# views_option_selected: "fa-light fa-check",
|
|
97
98
|
# views_option_menu: "fa-light fa-ellipsis",
|
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.3
|
|
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-
|
|
11
|
+
date: 2026-06-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -193,6 +193,7 @@ files:
|
|
|
193
193
|
- app/components/mensa/control_bar/component.css
|
|
194
194
|
- app/components/mensa/control_bar/component.html.erb
|
|
195
195
|
- app/components/mensa/control_bar/component.rb
|
|
196
|
+
- app/components/mensa/copyable/component_controller.js
|
|
196
197
|
- app/components/mensa/empty_state/component.css
|
|
197
198
|
- app/components/mensa/empty_state/component.html.erb
|
|
198
199
|
- app/components/mensa/empty_state/component.rb
|
|
@@ -294,6 +295,7 @@ files:
|
|
|
294
295
|
- db/migrate/20251112143558_add_description_to_table_view.rb
|
|
295
296
|
- db/migrate/20260604120000_create_mensa_exports.rb
|
|
296
297
|
- db/migrate/20260612110000_add_repeat_to_mensa_exports.rb
|
|
298
|
+
- db/migrate/20260616113603_add_password_to_export.rb
|
|
297
299
|
- docs/columns.png
|
|
298
300
|
- docs/export.png
|
|
299
301
|
- docs/filters.png
|