infotable 1.5.0 → 1.6.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 +144 -10
- data/app/assets/javascripts/infotable/controllers/drawer_controller.js +19 -18
- data/app/assets/javascripts/infotable/controllers/table_controller.js +42 -23
- data/app/controllers/infotable/tables_controller.rb +1 -1
- data/app/helpers/infotable/tables_helper.rb +10 -25
- data/app/views/infotable/tables/_filter_drawer.html.erb +6 -6
- data/app/views/infotable/tables/_pagination.html.erb +4 -7
- data/app/views/infotable/tables/_table.html.erb +1 -1
- data/app/views/infotable/tables/filters/_boolean.html.erb +1 -1
- data/app/views/infotable/tables/filters/_range.html.erb +1 -1
- data/app/views/infotable/tables/filters/_select.html.erb +2 -2
- data/app/views/infotable/tables/filters/_text.html.erb +2 -2
- data/config/locales/de.yml +126 -0
- data/config/locales/el.yml +126 -0
- data/config/locales/en.yml +18 -4
- data/config/locales/es.yml +126 -0
- data/config/locales/fr.yml +126 -0
- data/config/locales/it.yml +126 -0
- data/config/locales/pl.yml +18 -4
- data/exe/infotable-mcp +13 -0
- data/lib/generators/infotable/table/table_generator.rb +23 -1
- data/lib/generators/infotable/table/templates/table.rb.tt +8 -1
- data/lib/infotable/base.rb +5 -4
- data/lib/infotable/formatters/currency_formatter.rb +4 -12
- data/lib/infotable/formatters/date_formatter.rb +3 -9
- data/lib/infotable/formatters/duration_formatter.rb +51 -0
- data/lib/infotable/formatters/filesize_formatter.rb +14 -0
- data/lib/infotable/formatters/image_formatter.rb +31 -0
- data/lib/infotable/formatters/number_formatter.rb +46 -0
- data/lib/infotable/formatters/tags_formatter.rb +44 -0
- data/lib/infotable/formatters/truncate_formatter.rb +19 -0
- data/lib/infotable/mcp/introspection.rb +94 -0
- data/lib/infotable/mcp/server.rb +26 -0
- data/lib/infotable/mcp/table_checker.rb +80 -0
- data/lib/infotable/mcp/table_writer.rb +66 -0
- data/lib/infotable/mcp/tools.rb +122 -0
- data/lib/infotable/mcp.rb +30 -0
- data/lib/infotable/version.rb +1 -1
- data/lib/infotable.rb +22 -0
- metadata +51 -4
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module Infotable
|
|
2
|
+
module Mcp
|
|
3
|
+
# Loads a table and looks for mistakes before the app does: columns the model lacks,
|
|
4
|
+
# a default sort on a missing column, a query that raises. Optionally returns a few rows.
|
|
5
|
+
class TableChecker
|
|
6
|
+
def initialize(name: nil, source: nil, preview: 0)
|
|
7
|
+
@name = name
|
|
8
|
+
@source = source
|
|
9
|
+
@preview = preview.to_i.clamp(0, 20)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
table = load_table
|
|
14
|
+
problems = []
|
|
15
|
+
model = nil
|
|
16
|
+
|
|
17
|
+
begin
|
|
18
|
+
model = table.base_query.model
|
|
19
|
+
rescue StandardError => e
|
|
20
|
+
return { ok: false, problems: [ "query raises #{e.class}: #{e.message}" ] }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
problems.concat(column_problems(table, model))
|
|
24
|
+
problems.concat(sort_problems(table))
|
|
25
|
+
problems << "no authorize block: anyone who can reach the engine routes can read this table" if table.table_authorize.nil?
|
|
26
|
+
|
|
27
|
+
rows = preview_rows(table, problems)
|
|
28
|
+
{ ok: problems.none? { !_1.start_with?("no authorize") }, table: table.name, model: model.name, problems: problems, preview: rows }.compact
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def load_table
|
|
34
|
+
if @source
|
|
35
|
+
mod = Module.new
|
|
36
|
+
mod.module_eval(@source.sub(/class \S+ </, "class CheckedTable <"), "infotable_mcp_check.rb")
|
|
37
|
+
mod.const_get(:CheckedTable)
|
|
38
|
+
else
|
|
39
|
+
reload_app
|
|
40
|
+
Infotable::TableResolver.resolve(@name)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# A table written a moment ago is not known to the autoloader yet
|
|
45
|
+
def reload_app
|
|
46
|
+
Rails.application.reloader.reload! if Rails.application.config.enable_reloading
|
|
47
|
+
rescue StandardError
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def column_problems(table, model)
|
|
52
|
+
table.columns.filter_map do |col|
|
|
53
|
+
next if col[:value] || col[:virtual] || col[:sql] || %i[action actions].include?(col[:type])
|
|
54
|
+
next if model.column_names.include?(col[:name].to_s) || model.method_defined?(col[:name])
|
|
55
|
+
|
|
56
|
+
"column :#{col[:name]} is not an attribute of #{model.name}: add value:, sql: or virtual:"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def sort_problems(table)
|
|
61
|
+
column = table.sort_settings[:column]
|
|
62
|
+
return [] if column.nil? || table.columns.any? { _1[:name].to_s == column.to_s }
|
|
63
|
+
|
|
64
|
+
[ "default_sort :#{column} is not a defined column" ]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def preview_rows(table, problems)
|
|
68
|
+
return nil if @preview.zero?
|
|
69
|
+
|
|
70
|
+
columns = table.visible_columns.reject { %i[action actions].include?(_1[:type]) }
|
|
71
|
+
table.base_query.limit(@preview).map do |record|
|
|
72
|
+
columns.to_h { |col| [ col[:name], table.cell_value(record, col).to_s ] }
|
|
73
|
+
end
|
|
74
|
+
rescue StandardError => e
|
|
75
|
+
problems << "query raises #{e.class}: #{e.message}"
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require "generators/infotable/table/table_generator"
|
|
2
|
+
|
|
3
|
+
module Infotable
|
|
4
|
+
module Mcp
|
|
5
|
+
# Renders a table with the `infotable:table` generator into a scratch directory,
|
|
6
|
+
# so the code can be shown first and written to app/infotable only on request.
|
|
7
|
+
class TableWriter
|
|
8
|
+
Result = Struct.new(:path, :code, keyword_init: true)
|
|
9
|
+
|
|
10
|
+
class Error < StandardError; end
|
|
11
|
+
|
|
12
|
+
FLAGS = %i[only skip per_page sort toolbar row_click infinite_scroll countless checkbox authorize].freeze
|
|
13
|
+
|
|
14
|
+
def initialize(model, settings = {})
|
|
15
|
+
@model = model.to_s
|
|
16
|
+
@settings = settings.to_h.symbolize_keys.slice(*FLAGS).compact
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def render
|
|
20
|
+
raise Error, "unknown model #{@model}" unless @model.safe_constantize.is_a?(Class)
|
|
21
|
+
|
|
22
|
+
Dir.mktmpdir("infotable-mcp") do |dir|
|
|
23
|
+
shell = Thor::Base.shell.new
|
|
24
|
+
generator = Infotable::Generators::TableGenerator.new([ @model ], switches, destination_root: dir, shell: shell)
|
|
25
|
+
shell.mute { generator.invoke_all }
|
|
26
|
+
|
|
27
|
+
file = Dir.glob("app/infotable/**/*.rb", base: dir).first or raise Error, "the generator wrote nothing"
|
|
28
|
+
code = File.read(File.join(dir, file))
|
|
29
|
+
check_syntax!(code)
|
|
30
|
+
Result.new(path: file, code: code)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Writes the rendered table into the app; an existing file is only replaced with overwrite: true
|
|
35
|
+
def write(overwrite: false)
|
|
36
|
+
result = render
|
|
37
|
+
target = Rails.root.join(result.path)
|
|
38
|
+
raise Error, "#{result.path} already exists, pass overwrite: true to replace it" if target.exist? && !overwrite
|
|
39
|
+
|
|
40
|
+
target.dirname.mkpath
|
|
41
|
+
target.write(result.code)
|
|
42
|
+
result
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def switches
|
|
48
|
+
@settings.flat_map do |key, value|
|
|
49
|
+
flag = "--#{key.to_s.dasherize}"
|
|
50
|
+
case value
|
|
51
|
+
when true then [ flag ]
|
|
52
|
+
when false then [ "--no-#{key.to_s.dasherize}" ]
|
|
53
|
+
when Array then [ flag, *value.map(&:to_s) ]
|
|
54
|
+
else [ flag, value.to_s ]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def check_syntax!(code)
|
|
60
|
+
RubyVM::InstructionSequence.compile(code)
|
|
61
|
+
rescue SyntaxError => e
|
|
62
|
+
raise Error, "generated code does not parse (check authorize/sort values): #{e.message.lines.first&.strip}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module Infotable
|
|
2
|
+
module Mcp
|
|
3
|
+
class ListModels < ::MCP::Tool
|
|
4
|
+
tool_name "list_models"
|
|
5
|
+
description "Models of this Rails app with column types, enums and associations. Call first, so column names are not guessed."
|
|
6
|
+
input_schema(properties: {})
|
|
7
|
+
annotations(read_only_hint: true)
|
|
8
|
+
|
|
9
|
+
def self.call(server_context: nil)
|
|
10
|
+
Mcp.text(Introspection.models)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class ListTables < ::MCP::Tool
|
|
15
|
+
tool_name "list_tables"
|
|
16
|
+
description "InfoTable tables that already exist in app/infotable, with their columns and settings. Use them as the house style."
|
|
17
|
+
input_schema(properties: {})
|
|
18
|
+
annotations(read_only_hint: true)
|
|
19
|
+
|
|
20
|
+
def self.call(server_context: nil)
|
|
21
|
+
Mcp.text(Introspection.tables)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class DescribeDsl < ::MCP::Tool
|
|
26
|
+
tool_name "describe_dsl"
|
|
27
|
+
description "The table DSL of the installed infotable version: column options, types, filters, formatters, settings. The full guide is the infotable://readme resource."
|
|
28
|
+
input_schema(properties: {})
|
|
29
|
+
annotations(read_only_hint: true)
|
|
30
|
+
|
|
31
|
+
def self.call(server_context: nil)
|
|
32
|
+
Mcp.text(Introspection.dsl)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class TableOptions < ::MCP::Tool
|
|
37
|
+
tool_name "table_options"
|
|
38
|
+
description "Settings of a new table for a model, as questions with defaults proposed from the model. " \
|
|
39
|
+
"Ask the user these (all at once, defaults pre-filled) before calling generate_table."
|
|
40
|
+
input_schema(properties: { model: { type: "string", description: "Model class name, e.g. Order or Admin::Invoice" } }, required: [ "model" ])
|
|
41
|
+
annotations(read_only_hint: true)
|
|
42
|
+
|
|
43
|
+
def self.call(model:, server_context: nil)
|
|
44
|
+
Mcp.text(Introspection.table_options(model) || "#{model} is not an ActiveRecord model; call list_models")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class GenerateTable < ::MCP::Tool
|
|
49
|
+
tool_name "generate_table"
|
|
50
|
+
description "Generates app/infotable/<models>_table.rb for a model with the infotable:table generator. " \
|
|
51
|
+
"Shows the code only; set write: true to save it (refuses to replace a file unless overwrite: true). " \
|
|
52
|
+
"Answers from table_options map to the parameters. Run validate_table afterwards."
|
|
53
|
+
input_schema(
|
|
54
|
+
properties: {
|
|
55
|
+
model: { type: "string" },
|
|
56
|
+
only: { type: "array", items: { type: "string" }, description: "Only these columns" },
|
|
57
|
+
skip: { type: "array", items: { type: "string" }, description: "Leave these columns out" },
|
|
58
|
+
per_page: { type: "integer" },
|
|
59
|
+
sort: { type: "string", description: "column:direction, e.g. created_at:desc" },
|
|
60
|
+
toolbar: { type: "string", enum: %w[header rail] },
|
|
61
|
+
row_click: { type: "boolean" },
|
|
62
|
+
infinite_scroll: { type: "boolean" },
|
|
63
|
+
countless: { type: "boolean" },
|
|
64
|
+
checkbox: { type: "boolean" },
|
|
65
|
+
authorize: { type: "string", description: "Ruby expression over `controller`, e.g. controller.current_user&.admin?" },
|
|
66
|
+
write: { type: "boolean", description: "Save the file (default: only show the code)" },
|
|
67
|
+
overwrite: { type: "boolean" }
|
|
68
|
+
},
|
|
69
|
+
required: [ "model" ]
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def self.call(model:, write: false, overwrite: false, server_context: nil, **settings)
|
|
73
|
+
writer = TableWriter.new(model, settings)
|
|
74
|
+
result = write ? writer.write(overwrite: overwrite) : writer.render
|
|
75
|
+
Mcp.text(path: result.path, written: write, code: result.code)
|
|
76
|
+
rescue TableWriter::Error => e
|
|
77
|
+
Mcp.error(e.message)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class ValidateTable < ::MCP::Tool
|
|
82
|
+
tool_name "validate_table"
|
|
83
|
+
description "Loads a table (by name like posts_table, or from source code) and reports mistakes: missing columns, bad default sort, " \
|
|
84
|
+
"failing query. preview: N also returns the first N rows as the table would show them."
|
|
85
|
+
input_schema(
|
|
86
|
+
properties: {
|
|
87
|
+
name: { type: "string", description: "Table name, e.g. orders_table or admin_orders_table" },
|
|
88
|
+
source: { type: "string", description: "Table source code to check without saving it" },
|
|
89
|
+
preview: { type: "integer", description: "Rows to return (max 20)" }
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
annotations(read_only_hint: true)
|
|
93
|
+
|
|
94
|
+
def self.call(name: nil, source: nil, preview: 0, server_context: nil)
|
|
95
|
+
return Mcp.error("pass name or source") if name.blank? && source.blank?
|
|
96
|
+
|
|
97
|
+
Mcp.text(TableChecker.new(name: name, source: source, preview: preview).call)
|
|
98
|
+
rescue Infotable::TableResolver::NotFound, ScriptError, StandardError => e
|
|
99
|
+
Mcp.error("#{e.class}: #{e.message}")
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
class NewTablePrompt < ::MCP::Prompt
|
|
104
|
+
prompt_name "new_table"
|
|
105
|
+
description "Create an InfoTable table for a model, asking the user about its settings first"
|
|
106
|
+
arguments [ ::MCP::Prompt::Argument.new(name: "model", description: "Model class name", required: true) ]
|
|
107
|
+
|
|
108
|
+
def self.template(args, server_context: nil)
|
|
109
|
+
model = args["model"] || args[:model]
|
|
110
|
+
text = <<~TEXT
|
|
111
|
+
Create an InfoTable table for #{model}.
|
|
112
|
+
1. Call list_tables to see how tables in this app look, and table_options for #{model}.
|
|
113
|
+
2. Ask the user the questions of table_options in ONE message, with the proposed defaults filled in, and wait for the answers.
|
|
114
|
+
3. Call generate_table with the answers (without write) and show the code.
|
|
115
|
+
4. After the user agrees, call generate_table with write: true, then validate_table with preview: 5 and report the result.
|
|
116
|
+
Add a batch action, formatter or association column only when the user asks; describe_dsl lists what exists.
|
|
117
|
+
TEXT
|
|
118
|
+
::MCP::Prompt::Result.new(messages: [ ::MCP::Prompt::Message.new(role: "user", content: ::MCP::Content::Text.new(text)) ])
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require "mcp"
|
|
3
|
+
rescue LoadError
|
|
4
|
+
abort "infotable-mcp needs the mcp gem: add `gem \"mcp\", group: :development` to your Gemfile and run bundle install"
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require "json"
|
|
8
|
+
require "rails/generators"
|
|
9
|
+
require "tmpdir"
|
|
10
|
+
|
|
11
|
+
module Infotable
|
|
12
|
+
# MCP server for creating tables with an AI assistant. See exe/infotable-mcp.
|
|
13
|
+
module Mcp
|
|
14
|
+
autoload :Introspection, "infotable/mcp/introspection"
|
|
15
|
+
autoload :Server, "infotable/mcp/server"
|
|
16
|
+
autoload :TableWriter, "infotable/mcp/table_writer"
|
|
17
|
+
autoload :TableChecker, "infotable/mcp/table_checker"
|
|
18
|
+
|
|
19
|
+
def self.text(payload)
|
|
20
|
+
text = payload.is_a?(String) ? payload : JSON.pretty_generate(payload)
|
|
21
|
+
::MCP::Tool::Response.new([ { type: "text", text: text } ])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.error(message)
|
|
25
|
+
::MCP::Tool::Response.new([ { type: "text", text: message } ], error: true)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
require "infotable/mcp/tools"
|
data/lib/infotable/version.rb
CHANGED
data/lib/infotable.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "rails-i18n"
|
|
1
2
|
require "infotable/version"
|
|
2
3
|
require "infotable/configuration"
|
|
3
4
|
require "infotable/engine"
|
|
@@ -24,6 +25,27 @@ module Infotable
|
|
|
24
25
|
autoload :LinkFormatter, "infotable/formatters/link_formatter"
|
|
25
26
|
autoload :AvatarFormatter, "infotable/formatters/avatar_formatter"
|
|
26
27
|
autoload :PercentFormatter, "infotable/formatters/percent_formatter"
|
|
28
|
+
autoload :NumberFormatter, "infotable/formatters/number_formatter"
|
|
29
|
+
autoload :TagsFormatter, "infotable/formatters/tags_formatter"
|
|
30
|
+
autoload :TruncateFormatter, "infotable/formatters/truncate_formatter"
|
|
31
|
+
autoload :ImageFormatter, "infotable/formatters/image_formatter"
|
|
32
|
+
autoload :FilesizeFormatter, "infotable/formatters/filesize_formatter"
|
|
33
|
+
autoload :DurationFormatter, "infotable/formatters/duration_formatter"
|
|
34
|
+
|
|
35
|
+
# `formatter: :name` => class. Anything else is looked up as a custom "<Name>Formatter" constant.
|
|
36
|
+
def self.built_in
|
|
37
|
+
@built_in ||= {
|
|
38
|
+
date: DateFormatter, datetime: DateFormatter,
|
|
39
|
+
currency: CurrencyFormatter,
|
|
40
|
+
boolean: BooleanFormatter,
|
|
41
|
+
badge: BadgeFormatter, status: BadgeFormatter,
|
|
42
|
+
action: ActionFormatter, actions: ActionFormatter,
|
|
43
|
+
link: LinkFormatter, avatar: AvatarFormatter, percent: PercentFormatter,
|
|
44
|
+
number: NumberFormatter, tags: TagsFormatter, list: TagsFormatter,
|
|
45
|
+
truncate: TruncateFormatter, image: ImageFormatter,
|
|
46
|
+
filesize: FilesizeFormatter, duration: DurationFormatter
|
|
47
|
+
}.freeze
|
|
48
|
+
end
|
|
27
49
|
end
|
|
28
50
|
|
|
29
51
|
# Returns the root path of the InfoTable gem
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: infotable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jakub Cieślar
|
|
8
8
|
autorequire:
|
|
9
|
-
bindir:
|
|
9
|
+
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -24,6 +24,20 @@ dependencies:
|
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '8.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rails-i18n
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '8.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '8.0'
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: csv
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -122,12 +136,27 @@ dependencies:
|
|
|
122
136
|
- - ">="
|
|
123
137
|
- !ruby/object:Gem::Version
|
|
124
138
|
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: mcp
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
125
153
|
description: InfoTable provides server-side datatable functionality with filtering,
|
|
126
154
|
sorting, searching, and pagination. Built with Hotwire, Stimulus, and Tailwind CSS
|
|
127
155
|
for a modern, no-reload user experience.
|
|
128
156
|
email:
|
|
129
157
|
- jakub@infovation.pl
|
|
130
|
-
executables:
|
|
158
|
+
executables:
|
|
159
|
+
- infotable-mcp
|
|
131
160
|
extensions: []
|
|
132
161
|
extra_rdoc_files: []
|
|
133
162
|
files:
|
|
@@ -165,9 +194,15 @@ files:
|
|
|
165
194
|
- app/views/infotable/tables/show.html.erb
|
|
166
195
|
- app/views/layouts/infotable/application.html.erb
|
|
167
196
|
- config/importmap.rb
|
|
197
|
+
- config/locales/de.yml
|
|
198
|
+
- config/locales/el.yml
|
|
168
199
|
- config/locales/en.yml
|
|
200
|
+
- config/locales/es.yml
|
|
201
|
+
- config/locales/fr.yml
|
|
202
|
+
- config/locales/it.yml
|
|
169
203
|
- config/locales/pl.yml
|
|
170
204
|
- config/routes.rb
|
|
205
|
+
- exe/infotable-mcp
|
|
171
206
|
- lib/generators/infotable/install/install_generator.rb
|
|
172
207
|
- lib/generators/infotable/install/templates/initializer.rb
|
|
173
208
|
- lib/generators/infotable/install/templates/tailwind.config.js
|
|
@@ -186,8 +221,20 @@ files:
|
|
|
186
221
|
- lib/infotable/formatters/boolean_formatter.rb
|
|
187
222
|
- lib/infotable/formatters/currency_formatter.rb
|
|
188
223
|
- lib/infotable/formatters/date_formatter.rb
|
|
224
|
+
- lib/infotable/formatters/duration_formatter.rb
|
|
225
|
+
- lib/infotable/formatters/filesize_formatter.rb
|
|
226
|
+
- lib/infotable/formatters/image_formatter.rb
|
|
189
227
|
- lib/infotable/formatters/link_formatter.rb
|
|
228
|
+
- lib/infotable/formatters/number_formatter.rb
|
|
190
229
|
- lib/infotable/formatters/percent_formatter.rb
|
|
230
|
+
- lib/infotable/formatters/tags_formatter.rb
|
|
231
|
+
- lib/infotable/formatters/truncate_formatter.rb
|
|
232
|
+
- lib/infotable/mcp.rb
|
|
233
|
+
- lib/infotable/mcp/introspection.rb
|
|
234
|
+
- lib/infotable/mcp/server.rb
|
|
235
|
+
- lib/infotable/mcp/table_checker.rb
|
|
236
|
+
- lib/infotable/mcp/table_writer.rb
|
|
237
|
+
- lib/infotable/mcp/tools.rb
|
|
191
238
|
- lib/infotable/search_processor.rb
|
|
192
239
|
- lib/infotable/sql.rb
|
|
193
240
|
- lib/infotable/table_resolver.rb
|