infotable 1.0.1 → 1.3.0
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/README.md +29 -2
- data/app/assets/javascripts/infotable/controllers/drawer_controller.js +68 -42
- data/app/assets/javascripts/infotable/controllers/table_controller.js +276 -23
- data/app/controllers/infotable/tables_controller.rb +17 -7
- data/app/helpers/infotable/tables_helper.rb +64 -2
- data/app/views/infotable/tables/_active_filters.html.erb +24 -0
- data/app/views/infotable/tables/_column_visibility.html.erb +11 -11
- data/app/views/infotable/tables/_filter_drawer.html.erb +4 -4
- data/app/views/infotable/tables/_next_page_frame.html.erb +5 -5
- data/app/views/infotable/tables/_pagination.html.erb +12 -12
- data/app/views/infotable/tables/_rail.html.erb +56 -0
- data/app/views/infotable/tables/_side_panel.html.erb +22 -10
- data/app/views/infotable/tables/_table.html.erb +45 -28
- data/app/views/infotable/tables/_table_rows.html.erb +3 -3
- data/app/views/infotable/tables/filters/_boolean.html.erb +2 -2
- data/app/views/infotable/tables/filters/_date.html.erb +2 -30
- data/app/views/infotable/tables/filters/_number.html.erb +2 -32
- data/app/views/infotable/tables/filters/_range.html.erb +66 -0
- data/app/views/infotable/tables/filters/_select.html.erb +4 -4
- data/app/views/infotable/tables/filters/_text.html.erb +3 -3
- data/app/views/infotable/tables/show.html.erb +22 -13
- data/config/locales/en.yml +24 -0
- data/config/locales/pl.yml +24 -0
- data/config/routes.rb +1 -0
- data/lib/infotable/base.rb +80 -1
- data/lib/infotable/configuration.rb +3 -1
- data/lib/infotable/formatters/action_formatter.rb +7 -7
- data/lib/infotable/formatters/avatar_formatter.rb +2 -2
- data/lib/infotable/formatters/badge_formatter.rb +9 -9
- data/lib/infotable/formatters/boolean_formatter.rb +2 -2
- data/lib/infotable/formatters/link_formatter.rb +1 -1
- data/lib/infotable/formatters/percent_formatter.rb +1 -1
- data/lib/infotable/version.rb +1 -1
- metadata +4 -1
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
id="<%= infotable_filter_id(table_name, column, 'value') %>"
|
|
15
15
|
multiple
|
|
16
16
|
size="6"
|
|
17
|
-
class="block w-full appearance-none rounded-lg border-0 bg-white pl-3 py-2 pr-8 text-base sm:text-sm text-neutral-900 shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-600 focus:ring-offset-0 transition-all [box-shadow:inset_0_0_0_1px_rgb(212_212_212)] focus:[box-shadow:inset_0_0_0_2px_rgb(82_82_82)] cursor-pointer disabled:cursor-not-allowed disabled:bg-neutral-100 disabled:opacity-75"
|
|
17
|
+
class="block w-full appearance-none rounded-lg border-0 bg-white dark:bg-gray-900 pl-3 py-2 pr-8 text-base sm:text-sm text-neutral-900 dark:text-neutral-100 shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-600 focus:ring-offset-0 transition-all [box-shadow:inset_0_0_0_1px_rgb(212_212_212)] dark:[box-shadow:inset_0_0_0_1px_rgb(82_82_82)] focus:[box-shadow:inset_0_0_0_2px_rgb(82_82_82)] dark:focus:[box-shadow:inset_0_0_0_2px_rgb(163_163_163)] cursor-pointer disabled:cursor-not-allowed disabled:bg-neutral-100 disabled:opacity-75"
|
|
18
18
|
style="min-height: 120px;">
|
|
19
19
|
<% options.each do |option| %>
|
|
20
20
|
<% if option.is_a?(Array) %>
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
<% end %>
|
|
26
26
|
</select>
|
|
27
27
|
<button type="button"
|
|
28
|
-
class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 transition-colors"
|
|
28
|
+
class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
|
29
29
|
data-action="click->infotable--drawer#clearSingleFilter"
|
|
30
30
|
data-filter-name="<%= column[:name] %>"
|
|
31
31
|
data-filter-type="select"
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
<div class="relative">
|
|
42
42
|
<select name="filters[<%= column[:name] %>][value]"
|
|
43
43
|
id="<%= infotable_filter_id(table_name, column, 'value') %>"
|
|
44
|
-
class="block w-full appearance-none rounded-lg border-0 bg-white pr-10 pl-3 py-2 text-base sm:text-sm text-neutral-900 shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-600 focus:ring-offset-0 transition-all [box-shadow:inset_0_0_0_1px_rgb(212_212_212)] focus:[box-shadow:inset_0_0_0_2px_rgb(82_82_82)] cursor-pointer disabled:cursor-not-allowed disabled:bg-neutral-100 disabled:opacity-75 bg-[url('data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20fill=%27none%27%20viewBox=%270%200%2020%2020%27%3e%3cpath%20stroke=%27%23737373%27%20stroke-linecap=%27round%27%20stroke-linejoin=%27round%27%20stroke-width=%271.5%27%20d=%27M6%208l4%204%204-4%27/%3e%3c/svg%3e')] bg-[right_0.75rem_center] bg-no-repeat bg-[length:1.25em_1.25em]">
|
|
44
|
+
class="block w-full appearance-none rounded-lg border-0 bg-white dark:bg-gray-900 pr-10 pl-3 py-2 text-base sm:text-sm text-neutral-900 dark:text-neutral-100 shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-600 focus:ring-offset-0 transition-all [box-shadow:inset_0_0_0_1px_rgb(212_212_212)] dark:[box-shadow:inset_0_0_0_1px_rgb(82_82_82)] focus:[box-shadow:inset_0_0_0_2px_rgb(82_82_82)] dark:focus:[box-shadow:inset_0_0_0_2px_rgb(163_163_163)] cursor-pointer disabled:cursor-not-allowed disabled:bg-neutral-100 disabled:opacity-75 bg-[url('data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20fill=%27none%27%20viewBox=%270%200%2020%2020%27%3e%3cpath%20stroke=%27%23737373%27%20stroke-linecap=%27round%27%20stroke-linejoin=%27round%27%20stroke-width=%271.5%27%20d=%27M6%208l4%204%204-4%27/%3e%3c/svg%3e')] bg-[right_0.75rem_center] bg-no-repeat bg-[length:1.25em_1.25em]">
|
|
45
45
|
<option value=""><%= t('infotable.filters.all') %></option>
|
|
46
46
|
<% options.each do |option| %>
|
|
47
47
|
<% if option.is_a?(Array) %>
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
<% end %>
|
|
53
53
|
</select>
|
|
54
54
|
<button type="button"
|
|
55
|
-
class="absolute right-8 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors"
|
|
55
|
+
class="absolute right-8 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
|
56
56
|
data-action="click->infotable--drawer#clearSingleFilter"
|
|
57
57
|
data-filter-name="<%= column[:name] %>"
|
|
58
58
|
data-filter-type="select"
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
data-filter-op
|
|
7
7
|
data-action="change->infotable--drawer#syncFilterOps"
|
|
8
8
|
id="<%= infotable_filter_id(table_name, column, 'op') %>"
|
|
9
|
-
class="block w-full appearance-none rounded-lg border-0 bg-white pr-10 pl-3 py-2 text-base sm:text-sm text-neutral-900 shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-600 focus:ring-offset-0 transition-all [box-shadow:inset_0_0_0_1px_rgb(212_212_212)] focus:[box-shadow:inset_0_0_0_2px_rgb(82_82_82)] cursor-pointer disabled:cursor-not-allowed disabled:bg-neutral-100 disabled:opacity-75 bg-[url('data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20fill=%27none%27%20viewBox=%270%200%2020%2020%27%3e%3cpath%20stroke=%27%23737373%27%20stroke-linecap=%27round%27%20stroke-linejoin=%27round%27%20stroke-width=%271.5%27%20d=%27M6%208l4%204%204-4%27/%3e%3c/svg%3e')] bg-[right_0.75rem_center] bg-no-repeat bg-[length:1.25em_1.25em]">
|
|
9
|
+
class="block w-full appearance-none rounded-lg border-0 bg-white dark:bg-gray-900 pr-10 pl-3 py-2 text-base sm:text-sm text-neutral-900 dark:text-neutral-100 shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-600 focus:ring-offset-0 transition-all [box-shadow:inset_0_0_0_1px_rgb(212_212_212)] dark:[box-shadow:inset_0_0_0_1px_rgb(82_82_82)] focus:[box-shadow:inset_0_0_0_2px_rgb(82_82_82)] dark:focus:[box-shadow:inset_0_0_0_2px_rgb(163_163_163)] cursor-pointer disabled:cursor-not-allowed disabled:bg-neutral-100 disabled:opacity-75 bg-[url('data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20fill=%27none%27%20viewBox=%270%200%2020%2020%27%3e%3cpath%20stroke=%27%23737373%27%20stroke-linecap=%27round%27%20stroke-linejoin=%27round%27%20stroke-width=%271.5%27%20d=%27M6%208l4%204%204-4%27/%3e%3c/svg%3e')] bg-[right_0.75rem_center] bg-no-repeat bg-[length:1.25em_1.25em]">
|
|
10
10
|
<option value="contains"><%= t('infotable.filters.text_ops.contains') %></option>
|
|
11
11
|
<option value="exact"><%= t('infotable.filters.text_ops.exact') %></option>
|
|
12
12
|
<option value="not_contain"><%= t('infotable.filters.text_ops.not_contain') %></option>
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
name="filters[<%= column[:name] %>][value]"
|
|
24
24
|
id="<%= infotable_filter_id(table_name, column, 'value') %>"
|
|
25
25
|
placeholder="<%= t('infotable.filters.enter_value') %>"
|
|
26
|
-
class="block w-full rounded-lg border-0 bg-white pr-8 pl-3 py-2 text-base sm:text-sm text-neutral-900 placeholder:text-neutral-500 shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-600 focus:ring-offset-0 transition-all [box-shadow:inset_0_0_0_1px_rgb(212_212_212)] focus:[box-shadow:inset_0_0_0_2px_rgb(82_82_82)] disabled:cursor-not-allowed disabled:bg-neutral-100">
|
|
26
|
+
class="block w-full rounded-lg border-0 bg-white dark:bg-gray-900 pr-8 pl-3 py-2 text-base sm:text-sm text-neutral-900 dark:text-neutral-100 placeholder:text-neutral-500 shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-600 focus:ring-offset-0 transition-all [box-shadow:inset_0_0_0_1px_rgb(212_212_212)] dark:[box-shadow:inset_0_0_0_1px_rgb(82_82_82)] focus:[box-shadow:inset_0_0_0_2px_rgb(82_82_82)] dark:focus:[box-shadow:inset_0_0_0_2px_rgb(163_163_163)] disabled:cursor-not-allowed disabled:bg-neutral-100">
|
|
27
27
|
<button type="button"
|
|
28
|
-
class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors"
|
|
28
|
+
class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
|
29
29
|
data-action="click->infotable--drawer#clearSingleFilter"
|
|
30
30
|
data-filter-name="<%= column[:name] %>"
|
|
31
31
|
data-filter-type="text"
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
<%# This view renders inside the turbo frame %>
|
|
2
2
|
<%# Turbo requires the frame element to be present in the response %>
|
|
3
3
|
<turbo-frame id="<%= params[:table_name] %>_content">
|
|
4
|
-
|
|
4
|
+
<% active_filters = infotable_active_filters(@table_class, @filters, @search) %>
|
|
5
|
+
<%= render "infotable/tables/active_filters", chips: active_filters, table_name: params[:table_name] %>
|
|
6
|
+
<div<% if @pagy && !@table_class.countless? %> data-total-count="<%= @pagy.count %>"<% end %> class="relative overflow-y-auto overflow-x-auto scroll-smooth [scrollbar-width:thin] [scrollbar-color:#cbd5e1_#f1f5f9] [&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar]:h-2 [&::-webkit-scrollbar-track]:bg-slate-100 [&::-webkit-scrollbar-thumb]:bg-slate-300 [&::-webkit-scrollbar-thumb]:rounded [&::-webkit-scrollbar-thumb:hover]:bg-slate-400 dark:[scrollbar-color:#475569_#1e293b] dark:[&::-webkit-scrollbar-track]:bg-slate-800 dark:[&::-webkit-scrollbar-thumb]:bg-slate-600"
|
|
5
7
|
style="min-height: <%= @table_class.min_height %>; max-height: <%= @table_class.max_height %>;">
|
|
6
8
|
|
|
7
9
|
<% if @records.any? %>
|
|
8
10
|
<%# Table %>
|
|
9
|
-
<table class="min-w-full divide-y divide-gray-200">
|
|
10
|
-
<thead class="bg-gray-50 border-b-2 border-gray-200">
|
|
11
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
12
|
+
<thead class="bg-gray-50 dark:bg-gray-800 border-b-2 border-gray-200 dark:border-gray-700">
|
|
11
13
|
<tr>
|
|
12
14
|
<%
|
|
13
15
|
row_size = @table_class.row_size_value
|
|
@@ -18,12 +20,12 @@
|
|
|
18
20
|
end
|
|
19
21
|
%>
|
|
20
22
|
<% if @table_class.checkbox_enabled? %>
|
|
21
|
-
<th scope="col" class="<%= header_padding %> w-10 bg-gray-50 sticky top-0 z-20">
|
|
23
|
+
<th scope="col" class="<%= header_padding %> w-10 bg-gray-50 dark:bg-gray-800 sticky top-0 z-20">
|
|
22
24
|
<input type="checkbox"
|
|
23
25
|
aria-label="<%= t('infotable.batch.select_all') %>"
|
|
24
26
|
data-infotable--table-target="selectAll"
|
|
25
27
|
data-action="change->infotable--table#toggleAll"
|
|
26
|
-
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
|
|
28
|
+
class="h-4 w-4 rounded border-gray-300 dark:border-gray-600 text-indigo-600 dark:text-indigo-400 focus:ring-indigo-500">
|
|
27
29
|
</th>
|
|
28
30
|
<% end %>
|
|
29
31
|
<% @table_class.columns.each do |column| %>
|
|
@@ -32,7 +34,7 @@
|
|
|
32
34
|
data-default-visible="<%= column[:visible] %>"
|
|
33
35
|
<%= tag.attributes(data: { default_pinned: column[:pinned] }) if column[:pinned] %>
|
|
34
36
|
style="width: <%= column[:width] %>; max-width: <%= column[:width] %>; overflow: hidden;"
|
|
35
|
-
class="<%= header_padding %> text-left text-xs font-semibold text-gray-900 tracking-wider select-none bg-gray-50 sticky top-0 z-20">
|
|
37
|
+
class="<%= header_padding %> text-left text-xs font-semibold text-gray-900 dark:text-gray-100 tracking-wider select-none bg-gray-50 dark:bg-gray-800 sticky top-0 z-20">
|
|
36
38
|
<% if column[:sortable] %>
|
|
37
39
|
<% sort_index = current_sorts.index { |name, _| name == column[:name].to_s } %>
|
|
38
40
|
<% sort_dir = sort_index ? current_sorts[sort_index].last : nil %>
|
|
@@ -56,16 +58,16 @@
|
|
|
56
58
|
<span class="flex-none rounded">
|
|
57
59
|
<% if sort_index %>
|
|
58
60
|
<% if sort_dir == 'asc' %>
|
|
59
|
-
<svg class="h-4 w-4 text-indigo-600" fill="currentColor" viewBox="0 0 20 20">
|
|
61
|
+
<svg class="h-4 w-4 text-indigo-600 dark:text-indigo-400" fill="currentColor" viewBox="0 0 20 20">
|
|
60
62
|
<path fill-rule="evenodd" d="M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z" clip-rule="evenodd"/>
|
|
61
63
|
</svg>
|
|
62
64
|
<% else %>
|
|
63
|
-
<svg class="h-4 w-4 text-indigo-600" fill="currentColor" viewBox="0 0 20 20">
|
|
65
|
+
<svg class="h-4 w-4 text-indigo-600 dark:text-indigo-400" fill="currentColor" viewBox="0 0 20 20">
|
|
64
66
|
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
|
|
65
67
|
</svg>
|
|
66
68
|
<% end %>
|
|
67
69
|
<% if current_sorts.size > 1 %>
|
|
68
|
-
<span class="text-[10px] font-bold text-indigo-600"><%= sort_index + 1 %></span>
|
|
70
|
+
<span class="text-[10px] font-bold text-indigo-600 dark:text-indigo-400"><%= sort_index + 1 %></span>
|
|
69
71
|
<% end %>
|
|
70
72
|
<% else %>
|
|
71
73
|
<svg class="h-4 w-4 text-gray-400 opacity-0 group-hover:opacity-100 transition-opacity" fill="currentColor" viewBox="0 0 20 20">
|
|
@@ -81,7 +83,7 @@
|
|
|
81
83
|
<% end %>
|
|
82
84
|
</tr>
|
|
83
85
|
</thead>
|
|
84
|
-
<tbody id="<%= params[:table_name] %>_tbody" class="bg-white">
|
|
86
|
+
<tbody id="<%= params[:table_name] %>_tbody" class="bg-white dark:bg-gray-900">
|
|
85
87
|
<%= render partial: "infotable/tables/table_rows", locals: { records: @records, table_class: @table_class } %>
|
|
86
88
|
</tbody>
|
|
87
89
|
</table>
|
|
@@ -96,8 +98,15 @@
|
|
|
96
98
|
<svg class="mx-auto h-16 w-16 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
97
99
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"/>
|
|
98
100
|
</svg>
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
<% if active_filters.any? %>
|
|
102
|
+
<h3 class="mt-4 text-lg font-medium text-gray-900 dark:text-gray-100"><%= t('infotable.table.empty_state.filtered_title') %></h3>
|
|
103
|
+
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400"><%= t('infotable.table.empty_state.filtered_description') %></p>
|
|
104
|
+
<button type="button" data-action="click->infotable--table#clearAllFilters" data-empty-clear-filters
|
|
105
|
+
class="mt-4 inline-flex items-center rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 shadow-sm hover:bg-gray-50 dark:hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-indigo-500"><%= t('infotable.filters.active.clear_all') %></button>
|
|
106
|
+
<% else %>
|
|
107
|
+
<h3 class="mt-4 text-lg font-medium text-gray-900 dark:text-gray-100"><%= t('infotable.table.empty_state.title') %></h3>
|
|
108
|
+
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400"><%= t('infotable.table.empty_state.description') %></p>
|
|
109
|
+
<% end %>
|
|
101
110
|
</div>
|
|
102
111
|
<% end %>
|
|
103
112
|
|
|
@@ -105,7 +114,7 @@
|
|
|
105
114
|
|
|
106
115
|
<%# Pagination - Only visible when infinite scroll is disabled %>
|
|
107
116
|
<% unless @infinite_scroll_enabled %>
|
|
108
|
-
<div class="border-t border-gray-200 bg-white px-6 py-4">
|
|
117
|
+
<div class="border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-4 sm:px-6 py-4">
|
|
109
118
|
<%= render "infotable/tables/pagination", pagy: @pagy, table_name: params[:table_name] %>
|
|
110
119
|
</div>
|
|
111
120
|
<% end %>
|
data/config/locales/en.yml
CHANGED
|
@@ -5,14 +5,19 @@ en:
|
|
|
5
5
|
export_csv: "Export CSV"
|
|
6
6
|
filters: "Filters"
|
|
7
7
|
exporting: "Exporting..."
|
|
8
|
+
refresh: "Refresh"
|
|
9
|
+
columns: "Columns"
|
|
8
10
|
sort_hint: "Click to sort, Shift+click to add a column to the sort"
|
|
9
11
|
loading:
|
|
10
12
|
initial: "Loading data..."
|
|
11
13
|
more_items: "Loading more items..."
|
|
12
14
|
all_loaded: "All items loaded"
|
|
15
|
+
resize_column: "resize column"
|
|
13
16
|
empty_state:
|
|
14
17
|
title: "No data found"
|
|
15
18
|
description: "Get started by adding some records to see them here."
|
|
19
|
+
filtered_title: "No rows match your filters"
|
|
20
|
+
filtered_description: "Remove a filter or search for something else."
|
|
16
21
|
|
|
17
22
|
drawer:
|
|
18
23
|
label: "Filters and columns"
|
|
@@ -39,6 +44,10 @@ en:
|
|
|
39
44
|
clear_all: "Clear All"
|
|
40
45
|
apply_filters: "Apply Filters"
|
|
41
46
|
clear_filter: "Clear this filter"
|
|
47
|
+
active:
|
|
48
|
+
search: "Search: \u201c%{query}\u201d"
|
|
49
|
+
remove: "Remove filter %{filter}"
|
|
50
|
+
clear_all: "Clear all filters"
|
|
42
51
|
from: "From"
|
|
43
52
|
to: "To"
|
|
44
53
|
min: "Min"
|
|
@@ -60,6 +69,19 @@ en:
|
|
|
60
69
|
ends_with: "Ends with"
|
|
61
70
|
is_empty: "Is empty"
|
|
62
71
|
is_not_empty: "Is not empty"
|
|
72
|
+
range_ops:
|
|
73
|
+
between: "Between"
|
|
74
|
+
number_ops:
|
|
75
|
+
eq: "Equals"
|
|
76
|
+
neq: "Does not equal"
|
|
77
|
+
gt: "Greater than"
|
|
78
|
+
gte: "Greater than or equal"
|
|
79
|
+
lt: "Less than"
|
|
80
|
+
lte: "Less than or equal"
|
|
81
|
+
date_ops:
|
|
82
|
+
"on": "On"
|
|
83
|
+
before: "Before"
|
|
84
|
+
after: "After"
|
|
63
85
|
|
|
64
86
|
formatters:
|
|
65
87
|
ago: "%{time} ago"
|
|
@@ -73,6 +95,8 @@ en:
|
|
|
73
95
|
clear: "Clear selection"
|
|
74
96
|
select_all: "Select all rows"
|
|
75
97
|
select_row: "Select row"
|
|
98
|
+
select_all_matching: "Select all %{count} matching"
|
|
99
|
+
truncated: "Only the first %{max} rows are selected"
|
|
76
100
|
|
|
77
101
|
search:
|
|
78
102
|
placeholder: "Search..."
|
data/config/locales/pl.yml
CHANGED
|
@@ -5,14 +5,19 @@ pl:
|
|
|
5
5
|
export_csv: "Eksportuj CSV"
|
|
6
6
|
filters: "Filtry"
|
|
7
7
|
exporting: "Eksportowanie..."
|
|
8
|
+
refresh: "Odśwież"
|
|
9
|
+
columns: "Kolumny"
|
|
8
10
|
sort_hint: "Kliknij, aby sortować; Shift+klik dodaje kolumnę do sortowania"
|
|
9
11
|
loading:
|
|
10
12
|
initial: "Ładowanie danych..."
|
|
11
13
|
more_items: "Ładowanie kolejnych elementów..."
|
|
12
14
|
all_loaded: "Wszystkie elementy załadowane"
|
|
15
|
+
resize_column: "zmień szerokość kolumny"
|
|
13
16
|
empty_state:
|
|
14
17
|
title: "Nie znaleziono danych"
|
|
15
18
|
description: "Rozpocznij od dodania rekordów, aby zobaczyć je tutaj."
|
|
19
|
+
filtered_title: "Żaden wiersz nie pasuje do filtrów"
|
|
20
|
+
filtered_description: "Usuń filtr lub wyszukaj coś innego."
|
|
16
21
|
|
|
17
22
|
drawer:
|
|
18
23
|
label: "Filtry i kolumny"
|
|
@@ -39,6 +44,10 @@ pl:
|
|
|
39
44
|
clear_all: "Wyczyść wszystkie"
|
|
40
45
|
apply_filters: "Zastosuj filtry"
|
|
41
46
|
clear_filter: "Wyczyść ten filtr"
|
|
47
|
+
active:
|
|
48
|
+
search: "Szukaj: \u201e%{query}\u201d"
|
|
49
|
+
remove: "Usuń filtr %{filter}"
|
|
50
|
+
clear_all: "Wyczyść wszystkie filtry"
|
|
42
51
|
from: "Od"
|
|
43
52
|
to: "Do"
|
|
44
53
|
min: "Min"
|
|
@@ -60,6 +69,19 @@ pl:
|
|
|
60
69
|
ends_with: "Kończy się na"
|
|
61
70
|
is_empty: "Jest puste"
|
|
62
71
|
is_not_empty: "Nie jest puste"
|
|
72
|
+
range_ops:
|
|
73
|
+
between: "Pomiędzy"
|
|
74
|
+
number_ops:
|
|
75
|
+
eq: "Równa się"
|
|
76
|
+
neq: "Różne od"
|
|
77
|
+
gt: "Większe niż"
|
|
78
|
+
gte: "Większe lub równe"
|
|
79
|
+
lt: "Mniejsze niż"
|
|
80
|
+
lte: "Mniejsze lub równe"
|
|
81
|
+
date_ops:
|
|
82
|
+
"on": "W dniu"
|
|
83
|
+
before: "Przed"
|
|
84
|
+
after: "Po"
|
|
63
85
|
|
|
64
86
|
formatters:
|
|
65
87
|
ago: "%{time} temu"
|
|
@@ -72,6 +94,8 @@ pl:
|
|
|
72
94
|
selected: "Zaznaczono: %{count}"
|
|
73
95
|
clear: "Wyczyść zaznaczenie"
|
|
74
96
|
select_all: "Zaznacz wszystkie wiersze"
|
|
97
|
+
select_all_matching: "Zaznacz wszystkie pasujące (%{count})"
|
|
98
|
+
truncated: "Zaznaczono tylko pierwsze %{max} wierszy"
|
|
75
99
|
select_row: "Zaznacz wiersz"
|
|
76
100
|
|
|
77
101
|
search:
|
data/config/routes.rb
CHANGED
|
@@ -3,4 +3,5 @@ Infotable::Engine.routes.draw do
|
|
|
3
3
|
get "tables/:table_name", to: "tables#show", as: :table
|
|
4
4
|
get "tables/:table_name/data", to: "tables#data", as: :table_data
|
|
5
5
|
get "tables/:table_name/export", to: "tables#export", as: :table_export
|
|
6
|
+
get "tables/:table_name/ids", to: "tables#ids", as: :table_ids
|
|
6
7
|
end
|
data/lib/infotable/base.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Infotable
|
|
2
2
|
class Base
|
|
3
3
|
class << self
|
|
4
|
-
attr_accessor :table_columns, :table_query, :table_query_sql, :pagination_settings, :sort_settings, :height_settings, :infinite_scroll_settings, :row_link_settings, :slim_rows_settings, :row_size_settings, :filters_button_settings, :display_settings, :nil_value_settings, :empty_value_settings, :table_authorize, :checkbox_settings, :batch_action_list, :countless_setting, :url_state_setting
|
|
4
|
+
attr_accessor :table_columns, :table_query, :table_query_sql, :pagination_settings, :sort_settings, :height_settings, :infinite_scroll_settings, :row_link_settings, :slim_rows_settings, :row_size_settings, :filters_button_settings, :display_settings, :nil_value_settings, :empty_value_settings, :table_authorize, :checkbox_settings, :batch_action_list, :countless_setting, :url_state_setting, :resizable_columns_setting
|
|
5
5
|
|
|
6
6
|
def inherited(subclass)
|
|
7
7
|
super
|
|
@@ -45,6 +45,7 @@ module Infotable
|
|
|
45
45
|
subclass.batch_action_list = []
|
|
46
46
|
subclass.countless_setting = false
|
|
47
47
|
subclass.url_state_setting = nil
|
|
48
|
+
subclass.resizable_columns_setting = nil
|
|
48
49
|
|
|
49
50
|
inherit_from_parent(subclass)
|
|
50
51
|
end
|
|
@@ -62,6 +63,7 @@ module Infotable
|
|
|
62
63
|
subclass.batch_action_list = parent.batch_action_list.map(&:dup)
|
|
63
64
|
subclass.countless_setting = parent.countless_setting
|
|
64
65
|
subclass.url_state_setting = parent.url_state_setting
|
|
66
|
+
subclass.resizable_columns_setting = parent.resizable_columns_setting
|
|
65
67
|
%i[pagination_settings sort_settings height_settings infinite_scroll_settings row_link_settings
|
|
66
68
|
slim_rows_settings row_size_settings filters_button_settings display_settings
|
|
67
69
|
nil_value_settings empty_value_settings].each do |attr|
|
|
@@ -88,6 +90,17 @@ module Infotable
|
|
|
88
90
|
@url_state_setting = enabled
|
|
89
91
|
end
|
|
90
92
|
|
|
93
|
+
# Drag handles on the column headers (and arrow keys on the focused handle) to change
|
|
94
|
+
# column widths; widths are remembered per browser. Double-click resets one column.
|
|
95
|
+
# resizable_columns false
|
|
96
|
+
def resizable_columns(enabled = true)
|
|
97
|
+
@resizable_columns_setting = enabled
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def resizable_columns?
|
|
101
|
+
@resizable_columns_setting.nil? ? true : @resizable_columns_setting ? true : false
|
|
102
|
+
end
|
|
103
|
+
|
|
91
104
|
def url_state?
|
|
92
105
|
@url_state_setting.nil? ? Infotable.configuration.url_state : @url_state_setting ? true : false
|
|
93
106
|
end
|
|
@@ -116,6 +129,21 @@ module Infotable
|
|
|
116
129
|
record.public_send(@checkbox_settings[:id_method])
|
|
117
130
|
end
|
|
118
131
|
|
|
132
|
+
# Ids of every row the query matches (the "select all matching" button), at most `limit`.
|
|
133
|
+
# Plucks when the id method is a plain column of an ungrouped query, loads records otherwise.
|
|
134
|
+
def checkbox_ids(query, limit = nil)
|
|
135
|
+
method = @checkbox_settings[:id_method]
|
|
136
|
+
scope = query.reorder(nil)
|
|
137
|
+
scope = scope.limit(limit) if limit
|
|
138
|
+
model = query.model
|
|
139
|
+
|
|
140
|
+
if model.column_names.include?(method.to_s) && scope.group_values.empty? && scope.having_clause.empty?
|
|
141
|
+
scope.pluck(model.arel_table[method])
|
|
142
|
+
else
|
|
143
|
+
scope.map { |record| checkbox_value(record) }
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
119
147
|
# Per-table access check. Block receives the controller; falsy => 403.
|
|
120
148
|
# authorize { |controller| controller.current_user&.admin? }
|
|
121
149
|
def authorize(&block)
|
|
@@ -157,6 +185,7 @@ module Infotable
|
|
|
157
185
|
searchable: options.fetch(:searchable, false),
|
|
158
186
|
filterable: options.fetch(:filterable, false),
|
|
159
187
|
visible: options.fetch(:visible, true),
|
|
188
|
+
exportable: options.fetch(:exportable, !%i[action actions].include?(type)), # false keeps the column out of CSV exports
|
|
160
189
|
pinned: options[:pinned], # :left, :right, or nil
|
|
161
190
|
virtual: options.fetch(:virtual, false), # Virtual/computed columns (aggregates, subqueries)
|
|
162
191
|
virtual_sql: options[:virtual_sql], # SQL expression for aggregate columns (used in HAVING clause)
|
|
@@ -322,6 +351,26 @@ module Infotable
|
|
|
322
351
|
@filters_button_settings[:visible] = visible
|
|
323
352
|
end
|
|
324
353
|
|
|
354
|
+
# Where the controls live. :header (default) is the bar above the table with title, search,
|
|
355
|
+
# export and filters buttons. :rail hides that bar and puts filters, columns, export and
|
|
356
|
+
# refresh on a slim vertical rail at the table's right edge; search moves into the drawer.
|
|
357
|
+
# @example
|
|
358
|
+
# toolbar :rail
|
|
359
|
+
def toolbar(mode)
|
|
360
|
+
unless [ :header, :rail ].include?(mode)
|
|
361
|
+
raise ArgumentError, "Invalid toolbar: #{mode}. Must be one of header, rail"
|
|
362
|
+
end
|
|
363
|
+
@toolbar_setting = mode
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def toolbar_mode
|
|
367
|
+
@toolbar_setting || :header
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def rail_toolbar?
|
|
371
|
+
toolbar_mode == :rail
|
|
372
|
+
end
|
|
373
|
+
|
|
325
374
|
# Check if filters button is visible
|
|
326
375
|
def filters_button_visible?
|
|
327
376
|
@filters_button_settings ||= { visible: true }
|
|
@@ -444,6 +493,36 @@ module Infotable
|
|
|
444
493
|
columns.select { |col| col[:visible] }
|
|
445
494
|
end
|
|
446
495
|
|
|
496
|
+
# Columns a CSV export may contain (action columns and `exportable: false` are left out)
|
|
497
|
+
def exportable_columns
|
|
498
|
+
columns.select { |col| col[:exportable] }
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Which columns the CSV export contains and in which order, when the user has not chosen:
|
|
502
|
+
# export_columns :name, :email, :created_at
|
|
503
|
+
# Without it the export uses the visible, exportable columns in table order. With it, the
|
|
504
|
+
# list is also the pool the user can pick from (visible_columns can only narrow and reorder it).
|
|
505
|
+
def export_columns(*names)
|
|
506
|
+
@export_column_names = names.flatten.map(&:to_sym)
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def export_column_names
|
|
510
|
+
@export_column_names
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# The columns to export, as column definitions in export order. `requested` is the list of
|
|
514
|
+
# names the browser sends (the user's visible columns in their on-screen order).
|
|
515
|
+
def columns_for_export(requested = nil)
|
|
516
|
+
pool = exportable_columns
|
|
517
|
+
pool = export_column_names.map { |name| pool.find { |col| col[:name] == name } || raise(ArgumentError, "export_columns: unknown or non-exportable column #{name.inspect} in #{self.name}") } if export_column_names
|
|
518
|
+
|
|
519
|
+
by_name = pool.index_by { |col| col[:name].to_s }
|
|
520
|
+
picked = Array(requested).map { |name| by_name[name.to_s] }.compact.uniq
|
|
521
|
+
return picked if picked.any?
|
|
522
|
+
|
|
523
|
+
export_column_names ? pool : pool.select { |col| col[:visible] }
|
|
524
|
+
end
|
|
525
|
+
|
|
447
526
|
# Get sortable columns
|
|
448
527
|
def sortable_columns
|
|
449
528
|
columns.select { |col| col[:sortable] }
|
|
@@ -14,7 +14,8 @@ module Infotable
|
|
|
14
14
|
:empty_value,
|
|
15
15
|
:parent_controller,
|
|
16
16
|
:max_filter_options,
|
|
17
|
-
:url_state
|
|
17
|
+
:url_state,
|
|
18
|
+
:max_select_all
|
|
18
19
|
|
|
19
20
|
def initialize
|
|
20
21
|
@default_per_page = 25
|
|
@@ -30,6 +31,7 @@ module Infotable
|
|
|
30
31
|
@nil_value = "-" # Default placeholder for nil values
|
|
31
32
|
@empty_value = "-" # Default placeholder for empty strings
|
|
32
33
|
@url_state = true # mirror table state in the address bar
|
|
34
|
+
@max_select_all = 10_000 # "select all matching" collects at most this many ids (nil = no limit)
|
|
33
35
|
@max_filter_options = 500 # select filters render at most this many <option>s (nil = no limit)
|
|
34
36
|
@parent_controller = "ActionController::Base" # Set to "ApplicationController" to inherit host auth/filters
|
|
35
37
|
end
|
|
@@ -72,7 +72,7 @@ module Infotable
|
|
|
72
72
|
action[:label] || action[:icon] || view_context.t("infotable.formatters.action"),
|
|
73
73
|
resolve_url(action[:url], record),
|
|
74
74
|
role: "menuitem",
|
|
75
|
-
class: "block px-3 py-1.5 text-sm whitespace-nowrap #{link_classes(action[:color])} hover:bg-gray-50",
|
|
75
|
+
class: "block px-3 py-1.5 text-sm whitespace-nowrap #{link_classes(action[:color])} hover:bg-gray-50 dark:hover:bg-gray-800",
|
|
76
76
|
data: link_data(action[:data] || {}, action[:method] || :get, action[:confirm])
|
|
77
77
|
)
|
|
78
78
|
end
|
|
@@ -81,10 +81,10 @@ module Infotable
|
|
|
81
81
|
# <details> gives open/close and keyboard support without JS
|
|
82
82
|
content_tag(:details, class: "relative inline-block text-left") do
|
|
83
83
|
summary = content_tag(:summary, "\u22EF".html_safe,
|
|
84
|
-
class: "list-none cursor-pointer inline-flex items-center px-2 py-1 rounded-md border border-gray-300 bg-white text-gray-600 hover:bg-gray-50",
|
|
84
|
+
class: "list-none cursor-pointer inline-flex items-center px-2 py-1 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800",
|
|
85
85
|
"aria-label": view_context.t("infotable.formatters.action"), "aria-haspopup": "menu")
|
|
86
86
|
menu = content_tag(:div, role: "menu",
|
|
87
|
-
class: "absolute right-0 z-30 mt-1 min-w-36 rounded-md border border-gray-200 bg-white py-1 shadow-lg") do
|
|
87
|
+
class: "absolute right-0 z-30 mt-1 min-w-36 rounded-md border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 py-1 shadow-lg") do
|
|
88
88
|
safe_join(actions.map { |action| render_menu_item(action, record) })
|
|
89
89
|
end
|
|
90
90
|
summary + menu
|
|
@@ -110,7 +110,7 @@ module Infotable
|
|
|
110
110
|
when "success"
|
|
111
111
|
"border-green-600 bg-green-600 text-white hover:bg-green-700"
|
|
112
112
|
else
|
|
113
|
-
"border-gray-300 bg-white text-gray-700 hover:bg-gray-50"
|
|
113
|
+
"border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800"
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
"#{base} #{color_classes}"
|
|
@@ -119,11 +119,11 @@ module Infotable
|
|
|
119
119
|
def link_classes(color = nil)
|
|
120
120
|
case color&.to_s
|
|
121
121
|
when "danger"
|
|
122
|
-
"text-red-600 hover:text-red-900"
|
|
122
|
+
"text-red-600 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300"
|
|
123
123
|
when "success"
|
|
124
|
-
"text-green-600 hover:text-green-900"
|
|
124
|
+
"text-green-600 dark:text-green-400 hover:text-green-900 dark:hover:text-green-300"
|
|
125
125
|
else
|
|
126
|
-
"text-indigo-600 hover:text-indigo-900"
|
|
126
|
+
"text-indigo-600 dark:text-indigo-400 hover:text-indigo-900 dark:hover:text-indigo-200"
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
129
|
|
|
@@ -10,8 +10,8 @@ module Infotable
|
|
|
10
10
|
class AvatarFormatter < BaseFormatter
|
|
11
11
|
SIZES = { sm: "h-6 w-6 text-xs", md: "h-8 w-8 text-sm", lg: "h-10 w-10 text-base" }.freeze
|
|
12
12
|
COLORS = [
|
|
13
|
-
"bg-indigo-100 text-indigo-700", "bg-green-100 text-green-700", "bg-yellow-100 text-yellow-700",
|
|
14
|
-
"bg-pink-100 text-pink-700", "bg-blue-100 text-blue-700", "bg-purple-100 text-purple-700"
|
|
13
|
+
"bg-indigo-100 dark:bg-indigo-900/40 text-indigo-700 dark:text-indigo-300", "bg-green-100 dark:bg-green-900/40 text-green-700 dark:text-green-300", "bg-yellow-100 dark:bg-yellow-900/40 text-yellow-700 dark:text-yellow-300",
|
|
14
|
+
"bg-pink-100 dark:bg-pink-900/40 text-pink-700 dark:text-pink-300", "bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-300", "bg-purple-100 dark:bg-purple-900/40 text-purple-700 dark:text-purple-300"
|
|
15
15
|
].freeze
|
|
16
16
|
|
|
17
17
|
def format(value, record, options = {})
|
|
@@ -54,23 +54,23 @@ module Infotable
|
|
|
54
54
|
|
|
55
55
|
color_classes = case color.to_s
|
|
56
56
|
when "green"
|
|
57
|
-
"bg-green-100 text-green-800"
|
|
57
|
+
"bg-green-100 dark:bg-green-900/40 text-green-800 dark:text-green-300"
|
|
58
58
|
when "red"
|
|
59
|
-
"bg-red-100 text-red-800"
|
|
59
|
+
"bg-red-100 dark:bg-red-900/40 text-red-800 dark:text-red-300"
|
|
60
60
|
when "yellow"
|
|
61
|
-
"bg-yellow-100 text-yellow-800"
|
|
61
|
+
"bg-yellow-100 dark:bg-yellow-900/40 text-yellow-800 dark:text-yellow-300"
|
|
62
62
|
when "blue"
|
|
63
|
-
"bg-blue-100 text-blue-800"
|
|
63
|
+
"bg-blue-100 dark:bg-blue-900/40 text-blue-800 dark:text-blue-300"
|
|
64
64
|
when "indigo"
|
|
65
|
-
"bg-indigo-100 text-indigo-800"
|
|
65
|
+
"bg-indigo-100 dark:bg-indigo-900/40 text-indigo-800 dark:text-indigo-300"
|
|
66
66
|
when "purple"
|
|
67
|
-
"bg-purple-100 text-purple-800"
|
|
67
|
+
"bg-purple-100 dark:bg-purple-900/40 text-purple-800 dark:text-purple-300"
|
|
68
68
|
when "pink"
|
|
69
|
-
"bg-pink-100 text-pink-800"
|
|
69
|
+
"bg-pink-100 dark:bg-pink-900/40 text-pink-800 dark:text-pink-300"
|
|
70
70
|
when "cyan"
|
|
71
|
-
"bg-cyan-100 text-cyan-800"
|
|
71
|
+
"bg-cyan-100 dark:bg-cyan-900/40 text-cyan-800 dark:text-cyan-300"
|
|
72
72
|
else # gray
|
|
73
|
-
"bg-gray-100 text-gray-800"
|
|
73
|
+
"bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200"
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
"#{base} #{size_classes} #{color_classes}"
|
|
@@ -20,9 +20,9 @@ module Infotable
|
|
|
20
20
|
|
|
21
21
|
def format_as_badge(value, true_text, false_text)
|
|
22
22
|
if value
|
|
23
|
-
content_tag(:span, true_text, class: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800")
|
|
23
|
+
content_tag(:span, true_text, class: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 dark:bg-green-900/40 text-green-800 dark:text-green-300")
|
|
24
24
|
else
|
|
25
|
-
content_tag(:span, false_text, class: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800")
|
|
25
|
+
content_tag(:span, false_text, class: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200")
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -10,7 +10,7 @@ module Infotable
|
|
|
10
10
|
# Without url: the value itself is the URL (handy for website columns); mailto:/tel: work too.
|
|
11
11
|
class LinkFormatter < BaseFormatter
|
|
12
12
|
ALLOWED_SCHEMES = %w[http https mailto tel].freeze
|
|
13
|
-
DEFAULT_CLASSES = "text-indigo-600 hover:text-indigo-800 hover:underline".freeze
|
|
13
|
+
DEFAULT_CLASSES = "text-indigo-600 dark:text-indigo-400 hover:text-indigo-800 dark:hover:text-indigo-200 hover:underline".freeze
|
|
14
14
|
|
|
15
15
|
def format(value, record, options = {})
|
|
16
16
|
label = resolve(options[:label], record) || value
|
|
@@ -19,7 +19,7 @@ module Infotable
|
|
|
19
19
|
|
|
20
20
|
width = number.clamp(0, 100).round
|
|
21
21
|
bar = content_tag(:div, content_tag(:div, "", class: "h-full rounded-full bg-indigo-500", style: "width: #{width}%"),
|
|
22
|
-
class: "h-1.5 w-16 rounded-full bg-gray-200 flex-none", role: "presentation")
|
|
22
|
+
class: "h-1.5 w-16 rounded-full bg-gray-200 dark:bg-gray-700 flex-none", role: "presentation")
|
|
23
23
|
content_tag(:div, safe_join([ content_tag(:span, text, class: "tabular-nums"), bar ]), class: "flex items-center gap-2")
|
|
24
24
|
end
|
|
25
25
|
end
|
data/lib/infotable/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: infotable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jakub Cieślar
|
|
@@ -145,16 +145,19 @@ files:
|
|
|
145
145
|
- app/jobs/infotable/application_job.rb
|
|
146
146
|
- app/mailers/infotable/application_mailer.rb
|
|
147
147
|
- app/models/infotable/application_record.rb
|
|
148
|
+
- app/views/infotable/tables/_active_filters.html.erb
|
|
148
149
|
- app/views/infotable/tables/_column_visibility.html.erb
|
|
149
150
|
- app/views/infotable/tables/_filter_drawer.html.erb
|
|
150
151
|
- app/views/infotable/tables/_next_page_frame.html.erb
|
|
151
152
|
- app/views/infotable/tables/_pagination.html.erb
|
|
153
|
+
- app/views/infotable/tables/_rail.html.erb
|
|
152
154
|
- app/views/infotable/tables/_side_panel.html.erb
|
|
153
155
|
- app/views/infotable/tables/_table.html.erb
|
|
154
156
|
- app/views/infotable/tables/_table_rows.html.erb
|
|
155
157
|
- app/views/infotable/tables/filters/_boolean.html.erb
|
|
156
158
|
- app/views/infotable/tables/filters/_date.html.erb
|
|
157
159
|
- app/views/infotable/tables/filters/_number.html.erb
|
|
160
|
+
- app/views/infotable/tables/filters/_range.html.erb
|
|
158
161
|
- app/views/infotable/tables/filters/_select.html.erb
|
|
159
162
|
- app/views/infotable/tables/filters/_text.html.erb
|
|
160
163
|
- app/views/infotable/tables/show.html.erb
|