infotable 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1043 -0
- data/Rakefile +6 -0
- data/app/assets/javascripts/infotable/controllers/drawer_controller.js +1412 -0
- data/app/assets/javascripts/infotable/controllers/table_controller.js +921 -0
- data/app/assets/javascripts/infotable/index.js +14 -0
- data/app/controllers/infotable/application_controller.rb +4 -0
- data/app/controllers/infotable/tables_controller.rb +299 -0
- data/app/helpers/infotable/application_helper.rb +5 -0
- data/app/helpers/infotable/tables_helper.rb +354 -0
- data/app/jobs/infotable/application_job.rb +4 -0
- data/app/mailers/infotable/application_mailer.rb +6 -0
- data/app/models/infotable/application_record.rb +5 -0
- data/app/views/infotable/tables/_column_visibility.html.erb +100 -0
- data/app/views/infotable/tables/_filter_drawer.html.erb +65 -0
- data/app/views/infotable/tables/_next_page_frame.html.erb +39 -0
- data/app/views/infotable/tables/_pagination.html.erb +101 -0
- data/app/views/infotable/tables/_side_panel.html.erb +63 -0
- data/app/views/infotable/tables/_table.html.erb +135 -0
- data/app/views/infotable/tables/_table_rows.html.erb +38 -0
- data/app/views/infotable/tables/filters/_boolean.html.erb +22 -0
- data/app/views/infotable/tables/filters/_date.html.erb +30 -0
- data/app/views/infotable/tables/filters/_number.html.erb +32 -0
- data/app/views/infotable/tables/filters/_select.html.erb +68 -0
- data/app/views/infotable/tables/filters/_text.html.erb +38 -0
- data/app/views/infotable/tables/show.html.erb +113 -0
- data/app/views/layouts/infotable/application.html.erb +15 -0
- data/config/importmap.rb +6 -0
- data/config/locales/en.yml +88 -0
- data/config/locales/pl.yml +88 -0
- data/config/routes.rb +6 -0
- data/lib/generators/infotable/install/install_generator.rb +565 -0
- data/lib/generators/infotable/install/templates/TAILWIND_CONFIG.md +131 -0
- data/lib/generators/infotable/install/templates/initializer.rb +26 -0
- data/lib/generators/infotable/install/templates/tailwind.config.js +284 -0
- data/lib/generators/infotable/table/table_generator.rb +95 -0
- data/lib/generators/infotable/table/templates/table.rb.tt +26 -0
- data/lib/infotable/base.rb +463 -0
- data/lib/infotable/batch_actions.rb +34 -0
- data/lib/infotable/configuration.rb +53 -0
- data/lib/infotable/engine.rb +51 -0
- data/lib/infotable/filter_processor.rb +326 -0
- data/lib/infotable/formatters/action_formatter.rb +141 -0
- data/lib/infotable/formatters/avatar_formatter.rb +49 -0
- data/lib/infotable/formatters/badge_formatter.rb +80 -0
- data/lib/infotable/formatters/base_formatter.rb +47 -0
- data/lib/infotable/formatters/boolean_formatter.rb +38 -0
- data/lib/infotable/formatters/currency_formatter.rb +22 -0
- data/lib/infotable/formatters/date_formatter.rb +58 -0
- data/lib/infotable/formatters/link_formatter.rb +48 -0
- data/lib/infotable/formatters/percent_formatter.rb +27 -0
- data/lib/infotable/search_processor.rb +42 -0
- data/lib/infotable/table_resolver.rb +45 -0
- data/lib/infotable/version.rb +3 -0
- data/lib/infotable.rb +54 -0
- data/lib/tasks/infotable.rake +55 -0
- metadata +216 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Infotable
|
|
2
|
+
module Formatters
|
|
3
|
+
class CurrencyFormatter < BaseFormatter
|
|
4
|
+
def format(value, record, options = {})
|
|
5
|
+
return "" if value.blank?
|
|
6
|
+
|
|
7
|
+
unit = options[:unit] || "$"
|
|
8
|
+
precision = options[:precision] || 2
|
|
9
|
+
delimiter = options[:delimiter] || ","
|
|
10
|
+
separator = options[:separator] || "."
|
|
11
|
+
|
|
12
|
+
number_to_currency(
|
|
13
|
+
value,
|
|
14
|
+
unit: unit,
|
|
15
|
+
precision: precision,
|
|
16
|
+
delimiter: delimiter,
|
|
17
|
+
separator: separator
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Infotable
|
|
2
|
+
module Formatters
|
|
3
|
+
class DateFormatter < BaseFormatter
|
|
4
|
+
def format(value, record, options = {})
|
|
5
|
+
return "" if value.blank?
|
|
6
|
+
|
|
7
|
+
value = parse_value(value)
|
|
8
|
+
return value.to_s if value.is_a?(String)
|
|
9
|
+
|
|
10
|
+
format = options[:format] || :default
|
|
11
|
+
|
|
12
|
+
case format
|
|
13
|
+
when :short
|
|
14
|
+
value.strftime("%b %d, %Y")
|
|
15
|
+
when :long
|
|
16
|
+
value.strftime("%B %d, %Y")
|
|
17
|
+
when :time
|
|
18
|
+
value.strftime("%I:%M %p")
|
|
19
|
+
when :datetime
|
|
20
|
+
value.strftime("%b %d, %Y %I:%M %p")
|
|
21
|
+
when :relative
|
|
22
|
+
time_ago_in_words(value)
|
|
23
|
+
when :dot_date
|
|
24
|
+
value.strftime("%d.%m.%Y")
|
|
25
|
+
when :default
|
|
26
|
+
# Use Rails default
|
|
27
|
+
value.strftime("%Y-%m-%d %H:%M")
|
|
28
|
+
else
|
|
29
|
+
# Custom format string
|
|
30
|
+
if format.is_a?(String)
|
|
31
|
+
value.strftime(format)
|
|
32
|
+
else
|
|
33
|
+
# Try to use I18n localization
|
|
34
|
+
begin
|
|
35
|
+
view_context.l(value, format: format)
|
|
36
|
+
rescue
|
|
37
|
+
value.strftime("%Y-%m-%d %H:%M")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def parse_value(value)
|
|
46
|
+
return value unless value.is_a?(String)
|
|
47
|
+
|
|
48
|
+
Time.zone.parse(value) || value
|
|
49
|
+
rescue ArgumentError
|
|
50
|
+
value
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def time_ago_in_words(value)
|
|
54
|
+
view_context.t("infotable.formatters.ago", time: view_context.time_ago_in_words(value))
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Infotable
|
|
2
|
+
module Formatters
|
|
3
|
+
# formatter: :link
|
|
4
|
+
# formatter_options: {
|
|
5
|
+
# url: ->(record) { user_path(record) }, # Proc (run in the view), Symbol (helper method) or String
|
|
6
|
+
# label: ->(record) { record.email }, # optional, defaults to the cell value
|
|
7
|
+
# external: true, # target=_blank rel="noopener noreferrer"
|
|
8
|
+
# class: "..." # replaces the default classes
|
|
9
|
+
# }
|
|
10
|
+
# Without url: the value itself is the URL (handy for website columns); mailto:/tel: work too.
|
|
11
|
+
class LinkFormatter < BaseFormatter
|
|
12
|
+
ALLOWED_SCHEMES = %w[http https mailto tel].freeze
|
|
13
|
+
DEFAULT_CLASSES = "text-indigo-600 hover:text-indigo-800 hover:underline".freeze
|
|
14
|
+
|
|
15
|
+
def format(value, record, options = {})
|
|
16
|
+
label = resolve(options[:label], record) || value
|
|
17
|
+
return "" if label.blank? && value.blank?
|
|
18
|
+
|
|
19
|
+
url = options.key?(:url) ? resolve(options[:url], record) : value
|
|
20
|
+
return label.to_s unless self.class.safe_url?(url)
|
|
21
|
+
|
|
22
|
+
attributes = { href: url.to_s, class: options[:class] || DEFAULT_CLASSES }
|
|
23
|
+
attributes.merge!(target: "_blank", rel: "noopener noreferrer") if options[:external]
|
|
24
|
+
|
|
25
|
+
link_to(label.to_s, url.to_s, attributes)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Relative URLs, http(s), mailto and tel. Everything else (javascript:, data:, ...) is rendered as text.
|
|
29
|
+
def self.safe_url?(url)
|
|
30
|
+
return false if url.blank?
|
|
31
|
+
|
|
32
|
+
cleaned = url.to_s.gsub(/[[:cntrl:][:space:]]/, "")
|
|
33
|
+
scheme = cleaned[/\A([a-z][a-z0-9+.\-]*):/i, 1]
|
|
34
|
+
scheme.nil? || ALLOWED_SCHEMES.include?(scheme.downcase)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def resolve(option, record)
|
|
40
|
+
case option
|
|
41
|
+
when Proc then view_context.instance_exec(record, &option)
|
|
42
|
+
when Symbol then view_context.send(option, record)
|
|
43
|
+
else option
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Infotable
|
|
2
|
+
module Formatters
|
|
3
|
+
# formatter: :percent
|
|
4
|
+
# formatter_options: {
|
|
5
|
+
# precision: 1, # decimals, default 0
|
|
6
|
+
# scale: :percent, # :percent (value is 0-100, default) or :ratio (value is 0-1)
|
|
7
|
+
# bar: true # small progress bar next to the number
|
|
8
|
+
# }
|
|
9
|
+
class PercentFormatter < BaseFormatter
|
|
10
|
+
def format(value, record, options = {})
|
|
11
|
+
return "" if value.nil? || value == ""
|
|
12
|
+
|
|
13
|
+
number = Float(value.to_s, exception: false)
|
|
14
|
+
return value.to_s if number.nil?
|
|
15
|
+
|
|
16
|
+
number *= 100 if options[:scale].to_s == "ratio"
|
|
17
|
+
text = view_context.number_to_percentage(number, precision: options.fetch(:precision, 0), strip_insignificant_zeros: false)
|
|
18
|
+
return text unless options[:bar]
|
|
19
|
+
|
|
20
|
+
width = number.clamp(0, 100).round
|
|
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")
|
|
23
|
+
content_tag(:div, safe_join([ content_tag(:span, text, class: "tabular-nums"), bar ]), class: "flex items-center gap-2")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Infotable
|
|
2
|
+
# Global search: every whitespace-separated term must match (ILIKE) at least one
|
|
3
|
+
# searchable column. Non-text columns are matched on their text representation.
|
|
4
|
+
class SearchProcessor
|
|
5
|
+
MAX_TERMS = 5
|
|
6
|
+
MAX_TERM_LENGTH = 100
|
|
7
|
+
|
|
8
|
+
attr_reader :query, :table_class, :term
|
|
9
|
+
|
|
10
|
+
def initialize(query, table_class, term)
|
|
11
|
+
@query = query
|
|
12
|
+
@table_class = table_class
|
|
13
|
+
@term = term.to_s.delete("\u0000") # PostgreSQL rejects NUL bytes
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def apply
|
|
17
|
+
columns = searchable_columns
|
|
18
|
+
return query if columns.empty?
|
|
19
|
+
|
|
20
|
+
terms.reduce(query) do |relation, word|
|
|
21
|
+
pattern = "%#{ActiveRecord::Base.sanitize_sql_like(word)}%"
|
|
22
|
+
conditions = columns.map { "CAST(#{column_ref(_1)} AS text) ILIKE :pattern" }
|
|
23
|
+
relation.where(conditions.join(" OR "), pattern: pattern)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def terms
|
|
30
|
+
term.split.first(MAX_TERMS).map { _1.first(MAX_TERM_LENGTH) }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Aggregate (HAVING) columns can't be searched with WHERE
|
|
34
|
+
def searchable_columns
|
|
35
|
+
table_class.searchable_columns.reject { |col| col[:virtual] && col[:sql].blank? }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def column_ref(column)
|
|
39
|
+
column[:sql].presence || "#{query.model.table_name}.#{column[:name]}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Infotable
|
|
2
|
+
# Resolves a table name (:users_table, "cms_admins_users_table", "order_items_table")
|
|
3
|
+
# to its Infotable::Base subclass.
|
|
4
|
+
#
|
|
5
|
+
# Underscores are ambiguous (namespace separator or word separator), so every way of
|
|
6
|
+
# grouping the parts into namespaces is tried, flattest first:
|
|
7
|
+
# order_items -> OrderItemsTable, Order::ItemsTable, OrderItems::Table ...
|
|
8
|
+
# Only classes inheriting from Infotable::Base are accepted.
|
|
9
|
+
module TableResolver
|
|
10
|
+
MAX_PARTS = 8
|
|
11
|
+
|
|
12
|
+
class NotFound < Infotable::Error; end
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def resolve(table_name)
|
|
17
|
+
candidates(table_name).each do |class_name|
|
|
18
|
+
klass = class_name.safe_constantize
|
|
19
|
+
return klass if klass.is_a?(Class) && klass < Infotable::Base
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
raise NotFound, "Table '#{table_name}' not found. Make sure it's defined in app/infotable/"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def candidates(table_name)
|
|
26
|
+
return [] unless table_name.to_s.match?(/\A[a-z0-9]+(_[a-z0-9]+)*\z/i)
|
|
27
|
+
|
|
28
|
+
parts = table_name.to_s.sub(/_table\z/, "").split("_")
|
|
29
|
+
return [] if parts.empty? || parts.size > MAX_PARTS
|
|
30
|
+
|
|
31
|
+
(0...(2**(parts.size - 1))).map { |mask| segments(parts, mask) }
|
|
32
|
+
.sort_by(&:size)
|
|
33
|
+
.map { |segs| segs.map(&:camelize).join("::").sub(/([^:]+)\z/, '\1Table') }
|
|
34
|
+
.uniq
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Bit i of mask set => split between part i and i+1
|
|
38
|
+
def segments(parts, mask)
|
|
39
|
+
parts.each_with_index.each_with_object([ [] ]) do |(part, i), acc|
|
|
40
|
+
acc.last << part
|
|
41
|
+
acc << [] if i < parts.size - 1 && mask[i] == 1
|
|
42
|
+
end.map { |seg| seg.join("_") }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/infotable.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require "infotable/version"
|
|
2
|
+
require "infotable/configuration"
|
|
3
|
+
require "infotable/engine"
|
|
4
|
+
|
|
5
|
+
module Infotable
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
|
|
8
|
+
# Autoload core components
|
|
9
|
+
autoload :Base, "infotable/base"
|
|
10
|
+
autoload :FilterProcessor, "infotable/filter_processor"
|
|
11
|
+
autoload :BatchActions, "infotable/batch_actions"
|
|
12
|
+
autoload :SearchProcessor, "infotable/search_processor"
|
|
13
|
+
autoload :TableResolver, "infotable/table_resolver"
|
|
14
|
+
|
|
15
|
+
# Formatters
|
|
16
|
+
module Formatters
|
|
17
|
+
autoload :BaseFormatter, "infotable/formatters/base_formatter"
|
|
18
|
+
autoload :DateFormatter, "infotable/formatters/date_formatter"
|
|
19
|
+
autoload :CurrencyFormatter, "infotable/formatters/currency_formatter"
|
|
20
|
+
autoload :BooleanFormatter, "infotable/formatters/boolean_formatter"
|
|
21
|
+
autoload :BadgeFormatter, "infotable/formatters/badge_formatter"
|
|
22
|
+
autoload :ActionFormatter, "infotable/formatters/action_formatter"
|
|
23
|
+
autoload :LinkFormatter, "infotable/formatters/link_formatter"
|
|
24
|
+
autoload :AvatarFormatter, "infotable/formatters/avatar_formatter"
|
|
25
|
+
autoload :PercentFormatter, "infotable/formatters/percent_formatter"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns the root path of the InfoTable gem
|
|
29
|
+
def self.root
|
|
30
|
+
Engine.root
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the path to InfoTable views directory
|
|
34
|
+
# For use in Tailwind CSS @source directives via ERB
|
|
35
|
+
def self.views_path
|
|
36
|
+
root.join("app/views/infotable").to_s
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns the path to InfoTable formatters directory
|
|
40
|
+
# For use in Tailwind CSS @source directives via ERB
|
|
41
|
+
def self.formatters_path
|
|
42
|
+
root.join("lib/infotable/formatters").to_s
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns paths that should be scanned by Tailwind CSS
|
|
46
|
+
# For use with Node-based Tailwind (tailwind.config.js)
|
|
47
|
+
def self.tailwind_content_paths
|
|
48
|
+
[
|
|
49
|
+
root.join("app/views/infotable/**/*.{erb,html,rb}").to_s,
|
|
50
|
+
root.join("lib/infotable/formatters/**/*.rb").to_s,
|
|
51
|
+
root.join("app/assets/javascripts/infotable/**/*.js").to_s
|
|
52
|
+
]
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
namespace :infotable do
|
|
2
|
+
desc "Generate infotable.css from ERB template with resolved gem paths"
|
|
3
|
+
task generate_tailwind_sources: :environment do
|
|
4
|
+
# Find the ERB template
|
|
5
|
+
erb_path = if File.exist?("app/assets/stylesheets/infotable.css.erb")
|
|
6
|
+
"app/assets/stylesheets/infotable.css.erb"
|
|
7
|
+
elsif File.exist?("app/assets/tailwind/infotable.css.erb")
|
|
8
|
+
"app/assets/tailwind/infotable.css.erb"
|
|
9
|
+
else
|
|
10
|
+
puts "⚠️ infotable.css.erb not found. Run 'rails generate infotable:install' first."
|
|
11
|
+
next
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
output_path = erb_path.sub(".erb", "")
|
|
15
|
+
|
|
16
|
+
# Read and process the ERB template
|
|
17
|
+
require "erb"
|
|
18
|
+
template = File.read(erb_path)
|
|
19
|
+
result = ERB.new(template).result(binding)
|
|
20
|
+
|
|
21
|
+
# Write the generated CSS
|
|
22
|
+
File.write(output_path, result)
|
|
23
|
+
|
|
24
|
+
puts "✅ Generated #{output_path} from ERB template"
|
|
25
|
+
puts " Views: #{Infotable.views_path}"
|
|
26
|
+
puts " Formatters: #{Infotable.formatters_path}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Alias for backwards compatibility
|
|
30
|
+
task update_tailwind_paths: :generate_tailwind_sources
|
|
31
|
+
|
|
32
|
+
desc "Display InfoTable gem paths for Tailwind CSS (for debugging)"
|
|
33
|
+
task show_tailwind_paths: :environment do
|
|
34
|
+
puts "\n" + "=" * 60
|
|
35
|
+
puts "InfoTable Gem Paths"
|
|
36
|
+
puts "=" * 60
|
|
37
|
+
puts "Gem root: #{Infotable.root}"
|
|
38
|
+
puts "Views path: #{Infotable.views_path}"
|
|
39
|
+
puts "Formatters path: #{Infotable.formatters_path}"
|
|
40
|
+
puts "=" * 60 + "\n"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Hook into Tailwind CSS build tasks
|
|
45
|
+
if Rake::Task.task_defined?("tailwindcss:build")
|
|
46
|
+
Rake::Task["tailwindcss:build"].enhance([ "infotable:generate_tailwind_sources" ])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if Rake::Task.task_defined?("tailwindcss:watch")
|
|
50
|
+
Rake::Task["tailwindcss:watch"].enhance([ "infotable:generate_tailwind_sources" ])
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if Rake::Task.task_defined?("assets:precompile")
|
|
54
|
+
Rake::Task["assets:precompile"].enhance([ "infotable:generate_tailwind_sources" ])
|
|
55
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: infotable
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jakub Cieślar
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-10-25 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '8.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '8.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: csv
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: turbo-rails
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '2.0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '2.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: stimulus-rails
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1.3'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.3'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: pagy
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '43.0'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '43.0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: pg
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: puma
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: propshaft
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
description: InfoTable provides server-side datatable functionality with filtering,
|
|
126
|
+
sorting, searching, and pagination. Built with Hotwire, Stimulus, and Tailwind CSS
|
|
127
|
+
for a modern, no-reload user experience.
|
|
128
|
+
email:
|
|
129
|
+
- jakub@infovation.pl
|
|
130
|
+
executables: []
|
|
131
|
+
extensions: []
|
|
132
|
+
extra_rdoc_files: []
|
|
133
|
+
files:
|
|
134
|
+
- MIT-LICENSE
|
|
135
|
+
- README.md
|
|
136
|
+
- Rakefile
|
|
137
|
+
- app/assets/javascripts/infotable/controllers/drawer_controller.js
|
|
138
|
+
- app/assets/javascripts/infotable/controllers/table_controller.js
|
|
139
|
+
- app/assets/javascripts/infotable/index.js
|
|
140
|
+
- app/controllers/infotable/application_controller.rb
|
|
141
|
+
- app/controllers/infotable/tables_controller.rb
|
|
142
|
+
- app/helpers/infotable/application_helper.rb
|
|
143
|
+
- app/helpers/infotable/tables_helper.rb
|
|
144
|
+
- app/jobs/infotable/application_job.rb
|
|
145
|
+
- app/mailers/infotable/application_mailer.rb
|
|
146
|
+
- app/models/infotable/application_record.rb
|
|
147
|
+
- app/views/infotable/tables/_column_visibility.html.erb
|
|
148
|
+
- app/views/infotable/tables/_filter_drawer.html.erb
|
|
149
|
+
- app/views/infotable/tables/_next_page_frame.html.erb
|
|
150
|
+
- app/views/infotable/tables/_pagination.html.erb
|
|
151
|
+
- app/views/infotable/tables/_side_panel.html.erb
|
|
152
|
+
- app/views/infotable/tables/_table.html.erb
|
|
153
|
+
- app/views/infotable/tables/_table_rows.html.erb
|
|
154
|
+
- app/views/infotable/tables/filters/_boolean.html.erb
|
|
155
|
+
- app/views/infotable/tables/filters/_date.html.erb
|
|
156
|
+
- app/views/infotable/tables/filters/_number.html.erb
|
|
157
|
+
- app/views/infotable/tables/filters/_select.html.erb
|
|
158
|
+
- app/views/infotable/tables/filters/_text.html.erb
|
|
159
|
+
- app/views/infotable/tables/show.html.erb
|
|
160
|
+
- app/views/layouts/infotable/application.html.erb
|
|
161
|
+
- config/importmap.rb
|
|
162
|
+
- config/locales/en.yml
|
|
163
|
+
- config/locales/pl.yml
|
|
164
|
+
- config/routes.rb
|
|
165
|
+
- lib/generators/infotable/install/install_generator.rb
|
|
166
|
+
- lib/generators/infotable/install/templates/TAILWIND_CONFIG.md
|
|
167
|
+
- lib/generators/infotable/install/templates/initializer.rb
|
|
168
|
+
- lib/generators/infotable/install/templates/tailwind.config.js
|
|
169
|
+
- lib/generators/infotable/table/table_generator.rb
|
|
170
|
+
- lib/generators/infotable/table/templates/table.rb.tt
|
|
171
|
+
- lib/infotable.rb
|
|
172
|
+
- lib/infotable/base.rb
|
|
173
|
+
- lib/infotable/batch_actions.rb
|
|
174
|
+
- lib/infotable/configuration.rb
|
|
175
|
+
- lib/infotable/engine.rb
|
|
176
|
+
- lib/infotable/filter_processor.rb
|
|
177
|
+
- lib/infotable/formatters/action_formatter.rb
|
|
178
|
+
- lib/infotable/formatters/avatar_formatter.rb
|
|
179
|
+
- lib/infotable/formatters/badge_formatter.rb
|
|
180
|
+
- lib/infotable/formatters/base_formatter.rb
|
|
181
|
+
- lib/infotable/formatters/boolean_formatter.rb
|
|
182
|
+
- lib/infotable/formatters/currency_formatter.rb
|
|
183
|
+
- lib/infotable/formatters/date_formatter.rb
|
|
184
|
+
- lib/infotable/formatters/link_formatter.rb
|
|
185
|
+
- lib/infotable/formatters/percent_formatter.rb
|
|
186
|
+
- lib/infotable/search_processor.rb
|
|
187
|
+
- lib/infotable/table_resolver.rb
|
|
188
|
+
- lib/infotable/version.rb
|
|
189
|
+
- lib/tasks/infotable.rake
|
|
190
|
+
homepage: https://infotable.infovation.eu/
|
|
191
|
+
licenses:
|
|
192
|
+
- MIT
|
|
193
|
+
metadata:
|
|
194
|
+
homepage_uri: https://infotable.infovation.eu/
|
|
195
|
+
source_code_uri: https://github.com/jcieslar/infotable
|
|
196
|
+
changelog_uri: https://github.com/jcieslar/infotable/blob/main/CHANGELOG.md
|
|
197
|
+
post_install_message:
|
|
198
|
+
rdoc_options: []
|
|
199
|
+
require_paths:
|
|
200
|
+
- lib
|
|
201
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
202
|
+
requirements:
|
|
203
|
+
- - ">="
|
|
204
|
+
- !ruby/object:Gem::Version
|
|
205
|
+
version: '3.3'
|
|
206
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
|
+
requirements:
|
|
208
|
+
- - ">="
|
|
209
|
+
- !ruby/object:Gem::Version
|
|
210
|
+
version: '0'
|
|
211
|
+
requirements: []
|
|
212
|
+
rubygems_version: 3.5.16
|
|
213
|
+
signing_key:
|
|
214
|
+
specification_version: 4
|
|
215
|
+
summary: Modern, flexible datatable engine for Rails 8+ with Hotwire
|
|
216
|
+
test_files: []
|