infotable 1.4.1 → 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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +179 -11
  3. data/app/assets/javascripts/infotable/controllers/drawer_controller.js +74 -378
  4. data/app/assets/javascripts/infotable/controllers/table_controller.js +112 -120
  5. data/app/assets/javascripts/infotable/vendor/sortable.esm.js +3363 -0
  6. data/app/controllers/infotable/tables_controller.rb +16 -5
  7. data/app/helpers/infotable/tables_helper.rb +10 -48
  8. data/app/views/infotable/tables/_column_visibility.html.erb +4 -4
  9. data/app/views/infotable/tables/_end_indicator.html.erb +8 -0
  10. data/app/views/infotable/tables/_filter_drawer.html.erb +6 -6
  11. data/app/views/infotable/tables/_next_page_frame.html.erb +1 -9
  12. data/app/views/infotable/tables/_pagination.html.erb +4 -7
  13. data/app/views/infotable/tables/_table.html.erb +1 -1
  14. data/app/views/infotable/tables/_table_rows.html.erb +9 -2
  15. data/app/views/infotable/tables/filters/_boolean.html.erb +1 -1
  16. data/app/views/infotable/tables/filters/_range.html.erb +1 -1
  17. data/app/views/infotable/tables/filters/_select.html.erb +2 -2
  18. data/app/views/infotable/tables/filters/_text.html.erb +2 -2
  19. data/app/views/infotable/tables/show.html.erb +2 -2
  20. data/config/importmap.rb +2 -2
  21. data/config/locales/de.yml +126 -0
  22. data/config/locales/el.yml +126 -0
  23. data/config/locales/en.yml +18 -4
  24. data/config/locales/es.yml +126 -0
  25. data/config/locales/fr.yml +126 -0
  26. data/config/locales/it.yml +126 -0
  27. data/config/locales/pl.yml +18 -4
  28. data/exe/infotable-mcp +13 -0
  29. data/lib/generators/infotable/install/templates/initializer.rb +5 -3
  30. data/lib/generators/infotable/table/table_generator.rb +23 -1
  31. data/lib/generators/infotable/table/templates/table.rb.tt +8 -1
  32. data/lib/infotable/base.rb +62 -4
  33. data/lib/infotable/configuration.rb +1 -1
  34. data/lib/infotable/engine.rb +1 -8
  35. data/lib/infotable/filter_processor.rb +10 -1
  36. data/lib/infotable/formatters/boolean_formatter.rb +4 -4
  37. data/lib/infotable/formatters/currency_formatter.rb +4 -12
  38. data/lib/infotable/formatters/date_formatter.rb +3 -9
  39. data/lib/infotable/formatters/duration_formatter.rb +51 -0
  40. data/lib/infotable/formatters/filesize_formatter.rb +14 -0
  41. data/lib/infotable/formatters/image_formatter.rb +31 -0
  42. data/lib/infotable/formatters/number_formatter.rb +46 -0
  43. data/lib/infotable/formatters/tags_formatter.rb +44 -0
  44. data/lib/infotable/formatters/truncate_formatter.rb +19 -0
  45. data/lib/infotable/mcp/introspection.rb +94 -0
  46. data/lib/infotable/mcp/server.rb +26 -0
  47. data/lib/infotable/mcp/table_checker.rb +80 -0
  48. data/lib/infotable/mcp/table_writer.rb +66 -0
  49. data/lib/infotable/mcp/tools.rb +122 -0
  50. data/lib/infotable/mcp.rb +30 -0
  51. data/lib/infotable/table_resolver.rb +9 -0
  52. data/lib/infotable/version.rb +1 -1
  53. data/lib/infotable.rb +22 -0
  54. metadata +53 -4
@@ -0,0 +1,126 @@
1
+ el:
2
+ infotable:
3
+ table:
4
+ buttons:
5
+ export_csv: "Εξαγωγή CSV"
6
+ filters: "Φίλτρα"
7
+ exporting: "Εξαγωγή..."
8
+ refresh: "Ανανέωση"
9
+ columns: "Στήλες"
10
+ sort_hint: "Κάντε κλικ για ταξινόμηση, Shift+κλικ για προσθήκη στήλης στην ταξινόμηση"
11
+ loading:
12
+ initial: "Φόρτωση δεδομένων..."
13
+ more_items: "Φόρτωση περισσότερων στοιχείων..."
14
+ all_loaded: "Όλα τα στοιχεία φορτώθηκαν"
15
+ resize_column: "αλλαγή πλάτους στήλης"
16
+ empty_state:
17
+ title: "Δεν βρέθηκαν δεδομένα"
18
+ description: "Προσθέστε εγγραφές για να τις δείτε εδώ."
19
+ filtered_title: "Καμία γραμμή δεν ταιριάζει με τα φίλτρα σας"
20
+ filtered_description: "Αφαιρέστε ένα φίλτρο ή αναζητήστε κάτι άλλο."
21
+
22
+ drawer:
23
+ label: "Φίλτρα και στήλες"
24
+ panel_title:
25
+ customize_columns: "Προσαρμογή στηλών"
26
+ filters: "Φίλτρα"
27
+ columns: "Στήλες"
28
+ tabs:
29
+ filters: "Φίλτρα"
30
+ columns: "Στήλες"
31
+
32
+ columns:
33
+ instructions: "Σύρετε για αναδιάταξη, καρφιτσώστε στήλες και εμφανίστε/αποκρύψτε:"
34
+ pin:
35
+ left: "Καρφίτσωμα αριστερά"
36
+ right: "Καρφίτσωμα δεξιά"
37
+ actions:
38
+ select_all: "Επιλογή όλων"
39
+ deselect_all: "Αποεπιλογή όλων"
40
+ reset_to_defaults: "🔄 Επαναφορά προεπιλογών"
41
+
42
+ filters:
43
+ actions:
44
+ clear_all: "Εκκαθάριση όλων"
45
+ apply_filters: "Εφαρμογή φίλτρων"
46
+ clear_filter: "Εκκαθάριση αυτού του φίλτρου"
47
+ active:
48
+ search: "Αναζήτηση: «%{query}»"
49
+ remove: "Αφαίρεση φίλτρου %{filter}"
50
+ clear_all: "Εκκαθάριση όλων των φίλτρων"
51
+ from: "Από"
52
+ to: "Έως"
53
+ min: "Ελάχ."
54
+ max: "Μέγ."
55
+ enter_value: "Εισαγάγετε τιμή..."
56
+ all: "Όλα"
57
+ multi_select_hint: "Κρατήστε πατημένο το Ctrl/Cmd για πολλαπλή επιλογή"
58
+ options_truncated: "Εμφανίζονται οι πρώτες %{shown} από %{total} επιλογές"
59
+ boolean:
60
+ "true": "Αληθές"
61
+ "false": "Ψευδές"
62
+ empty: "Κενό"
63
+ not_empty: "Μη κενό"
64
+ text_ops:
65
+ contains: "Περιέχει"
66
+ exact: "Ακριβής αντιστοιχία"
67
+ not_contain: "Δεν περιέχει"
68
+ starts_with: "Ξεκινά με"
69
+ ends_with: "Τελειώνει σε"
70
+ is_empty: "Είναι κενό"
71
+ is_not_empty: "Δεν είναι κενό"
72
+ range_ops:
73
+ between: "Μεταξύ"
74
+ number_ops:
75
+ eq: "Ίσο με"
76
+ neq: "Διάφορο του"
77
+ gt: "Μεγαλύτερο από"
78
+ gte: "Μεγαλύτερο ή ίσο με"
79
+ lt: "Μικρότερο από"
80
+ lte: "Μικρότερο ή ίσο με"
81
+ date_ops:
82
+ "on": "Στις"
83
+ before: "Πριν από"
84
+ after: "Μετά από"
85
+
86
+ formatters:
87
+ ago: "πριν από %{time}"
88
+ date:
89
+ short: "%d %b %Y"
90
+ long: "%d %B %Y"
91
+ time: "%H:%M"
92
+ datetime: "%d %b %Y %H:%M"
93
+ action: "Ενέργεια"
94
+ boolean:
95
+ "true": "Ναι"
96
+ "false": "Όχι"
97
+ duration:
98
+ short:
99
+ d: "%{count} ημ."
100
+ h: "%{count} ώ."
101
+ m: "%{count} λ."
102
+ s: "%{count} δ."
103
+ long:
104
+ d: { one: "%{count} ημέρα", few: "%{count} ημέρες", many: "%{count} ημέρες", other: "%{count} ημέρες" }
105
+ h: { one: "%{count} ώρα", few: "%{count} ώρες", many: "%{count} ώρες", other: "%{count} ώρες" }
106
+ m: { one: "%{count} λεπτό", few: "%{count} λεπτά", many: "%{count} λεπτά", other: "%{count} λεπτά" }
107
+ s: { one: "%{count} δευτερόλεπτο", few: "%{count} δευτερόλεπτα", many: "%{count} δευτερόλεπτα", other: "%{count} δευτερόλεπτα" }
108
+
109
+ batch:
110
+ selected: "%{count} επιλεγμένα"
111
+ clear: "Εκκαθάριση επιλογής"
112
+ select_all: "Επιλογή όλων των γραμμών"
113
+ select_row: "Επιλογή γραμμής"
114
+ select_all_matching: "Επιλογή και των %{count} αποτελεσμάτων"
115
+ truncated: "Επιλέχθηκαν μόνο οι πρώτες %{max} γραμμές"
116
+
117
+ search:
118
+ placeholder: "Αναζήτηση..."
119
+ label: "Αναζήτηση στον πίνακα"
120
+
121
+ pagination:
122
+ summary_html: "Εμφάνιση %{from} έως %{to} από %{total} αποτελέσματα"
123
+ summary_no_total_html: "Εμφάνιση %{from} έως %{to}"
124
+ rows_per_page: "Γραμμές ανά σελίδα:"
125
+ previous: "Προηγούμενη"
126
+ next: "Επόμενη"
@@ -85,10 +85,26 @@ en:
85
85
 
86
86
  formatters:
87
87
  ago: "%{time} ago"
88
+ date:
89
+ short: "%b %d, %Y"
90
+ long: "%B %d, %Y"
91
+ time: "%I:%M %p"
92
+ datetime: "%b %d, %Y %I:%M %p"
88
93
  action: "Action"
89
94
  boolean:
90
95
  "true": "Yes"
91
96
  "false": "No"
97
+ duration:
98
+ short:
99
+ d: "%{count}d"
100
+ h: "%{count}h"
101
+ m: "%{count}m"
102
+ s: "%{count}s"
103
+ long:
104
+ d: { one: "%{count} day", few: "%{count} days", many: "%{count} days", other: "%{count} days" }
105
+ h: { one: "%{count} hour", few: "%{count} hours", many: "%{count} hours", other: "%{count} hours" }
106
+ m: { one: "%{count} minute", few: "%{count} minutes", many: "%{count} minutes", other: "%{count} minutes" }
107
+ s: { one: "%{count} second", few: "%{count} seconds", many: "%{count} seconds", other: "%{count} seconds" }
92
108
 
93
109
  batch:
94
110
  selected: "%{count} selected"
@@ -103,10 +119,8 @@ en:
103
119
  label: "Search table"
104
120
 
105
121
  pagination:
106
- showing: "Showing"
107
- to: "to"
108
- of: "of"
109
- results: "results"
122
+ summary_html: "Showing %{from} to %{to} of %{total} results"
123
+ summary_no_total_html: "Showing %{from} to %{to}"
110
124
  rows_per_page: "Rows per page:"
111
125
  previous: "Previous"
112
126
  next: "Next"
@@ -0,0 +1,126 @@
1
+ es:
2
+ infotable:
3
+ table:
4
+ buttons:
5
+ export_csv: "Exportar CSV"
6
+ filters: "Filtros"
7
+ exporting: "Exportando..."
8
+ refresh: "Actualizar"
9
+ columns: "Columnas"
10
+ sort_hint: "Haz clic para ordenar, Mayús+clic añade una columna al orden"
11
+ loading:
12
+ initial: "Cargando datos..."
13
+ more_items: "Cargando más elementos..."
14
+ all_loaded: "Todos los elementos cargados"
15
+ resize_column: "cambiar el ancho de la columna"
16
+ empty_state:
17
+ title: "No se encontraron datos"
18
+ description: "Añade algunos registros para verlos aquí."
19
+ filtered_title: "Ninguna fila coincide con tus filtros"
20
+ filtered_description: "Quita un filtro o busca otra cosa."
21
+
22
+ drawer:
23
+ label: "Filtros y columnas"
24
+ panel_title:
25
+ customize_columns: "Personalizar columnas"
26
+ filters: "Filtros"
27
+ columns: "Columnas"
28
+ tabs:
29
+ filters: "Filtros"
30
+ columns: "Columnas"
31
+
32
+ columns:
33
+ instructions: "Arrastra para reordenar, fija columnas y muestra/oculta:"
34
+ pin:
35
+ left: "Fijar a la izquierda"
36
+ right: "Fijar a la derecha"
37
+ actions:
38
+ select_all: "Seleccionar todo"
39
+ deselect_all: "Deseleccionar todo"
40
+ reset_to_defaults: "🔄 Restablecer valores predeterminados"
41
+
42
+ filters:
43
+ actions:
44
+ clear_all: "Borrar todo"
45
+ apply_filters: "Aplicar filtros"
46
+ clear_filter: "Borrar este filtro"
47
+ active:
48
+ search: "Búsqueda: «%{query}»"
49
+ remove: "Quitar el filtro %{filter}"
50
+ clear_all: "Borrar todos los filtros"
51
+ from: "Desde"
52
+ to: "Hasta"
53
+ min: "Mín"
54
+ max: "Máx"
55
+ enter_value: "Introduce un valor..."
56
+ all: "Todos"
57
+ multi_select_hint: "Mantén Ctrl/Cmd para seleccionar varios"
58
+ options_truncated: "Mostrando las primeras %{shown} de %{total} opciones"
59
+ boolean:
60
+ "true": "Verdadero"
61
+ "false": "Falso"
62
+ empty: "Vacío"
63
+ not_empty: "No vacío"
64
+ text_ops:
65
+ contains: "Contiene"
66
+ exact: "Coincidencia exacta"
67
+ not_contain: "No contiene"
68
+ starts_with: "Empieza por"
69
+ ends_with: "Termina en"
70
+ is_empty: "Está vacío"
71
+ is_not_empty: "No está vacío"
72
+ range_ops:
73
+ between: "Entre"
74
+ number_ops:
75
+ eq: "Igual a"
76
+ neq: "Distinto de"
77
+ gt: "Mayor que"
78
+ gte: "Mayor o igual que"
79
+ lt: "Menor que"
80
+ lte: "Menor o igual que"
81
+ date_ops:
82
+ "on": "El"
83
+ before: "Antes de"
84
+ after: "Después de"
85
+
86
+ formatters:
87
+ ago: "hace %{time}"
88
+ date:
89
+ short: "%d %b %Y"
90
+ long: "%d de %B de %Y"
91
+ time: "%H:%M"
92
+ datetime: "%d %b %Y %H:%M"
93
+ action: "Acción"
94
+ boolean:
95
+ "true": "Sí"
96
+ "false": "No"
97
+ duration:
98
+ short:
99
+ d: "%{count} d"
100
+ h: "%{count} h"
101
+ m: "%{count} min"
102
+ s: "%{count} s"
103
+ long:
104
+ d: { one: "%{count} día", few: "%{count} días", many: "%{count} días", other: "%{count} días" }
105
+ h: { one: "%{count} hora", few: "%{count} horas", many: "%{count} horas", other: "%{count} horas" }
106
+ m: { one: "%{count} minuto", few: "%{count} minutos", many: "%{count} minutos", other: "%{count} minutos" }
107
+ s: { one: "%{count} segundo", few: "%{count} segundos", many: "%{count} segundos", other: "%{count} segundos" }
108
+
109
+ batch:
110
+ selected: "%{count} seleccionados"
111
+ clear: "Borrar selección"
112
+ select_all: "Seleccionar todas las filas"
113
+ select_row: "Seleccionar fila"
114
+ select_all_matching: "Seleccionar los %{count} resultados"
115
+ truncated: "Solo se han seleccionado las primeras %{max} filas"
116
+
117
+ search:
118
+ placeholder: "Buscar..."
119
+ label: "Buscar en la tabla"
120
+
121
+ pagination:
122
+ summary_html: "Mostrando %{from} a %{to} de %{total} resultados"
123
+ summary_no_total_html: "Mostrando %{from} a %{to}"
124
+ rows_per_page: "Filas por página:"
125
+ previous: "Anterior"
126
+ next: "Siguiente"
@@ -0,0 +1,126 @@
1
+ fr:
2
+ infotable:
3
+ table:
4
+ buttons:
5
+ export_csv: "Exporter en CSV"
6
+ filters: "Filtres"
7
+ exporting: "Exportation..."
8
+ refresh: "Actualiser"
9
+ columns: "Colonnes"
10
+ sort_hint: "Cliquez pour trier, Maj+clic ajoute une colonne au tri"
11
+ loading:
12
+ initial: "Chargement des données..."
13
+ more_items: "Chargement d'autres éléments..."
14
+ all_loaded: "Tous les éléments sont chargés"
15
+ resize_column: "redimensionner la colonne"
16
+ empty_state:
17
+ title: "Aucune donnée trouvée"
18
+ description: "Ajoutez des enregistrements pour les voir ici."
19
+ filtered_title: "Aucune ligne ne correspond à vos filtres"
20
+ filtered_description: "Retirez un filtre ou cherchez autre chose."
21
+
22
+ drawer:
23
+ label: "Filtres et colonnes"
24
+ panel_title:
25
+ customize_columns: "Personnaliser les colonnes"
26
+ filters: "Filtres"
27
+ columns: "Colonnes"
28
+ tabs:
29
+ filters: "Filtres"
30
+ columns: "Colonnes"
31
+
32
+ columns:
33
+ instructions: "Glissez pour réorganiser, épinglez des colonnes et affichez/masquez :"
34
+ pin:
35
+ left: "Épingler à gauche"
36
+ right: "Épingler à droite"
37
+ actions:
38
+ select_all: "Tout sélectionner"
39
+ deselect_all: "Tout désélectionner"
40
+ reset_to_defaults: "🔄 Rétablir les valeurs par défaut"
41
+
42
+ filters:
43
+ actions:
44
+ clear_all: "Tout effacer"
45
+ apply_filters: "Appliquer les filtres"
46
+ clear_filter: "Effacer ce filtre"
47
+ active:
48
+ search: "Recherche : « %{query} »"
49
+ remove: "Retirer le filtre %{filter}"
50
+ clear_all: "Effacer tous les filtres"
51
+ from: "De"
52
+ to: "À"
53
+ min: "Min"
54
+ max: "Max"
55
+ enter_value: "Saisissez une valeur..."
56
+ all: "Tous"
57
+ multi_select_hint: "Maintenez Ctrl/Cmd pour en sélectionner plusieurs"
58
+ options_truncated: "Affichage des %{shown} premières options sur %{total}"
59
+ boolean:
60
+ "true": "Vrai"
61
+ "false": "Faux"
62
+ empty: "Vide"
63
+ not_empty: "Non vide"
64
+ text_ops:
65
+ contains: "Contient"
66
+ exact: "Correspondance exacte"
67
+ not_contain: "Ne contient pas"
68
+ starts_with: "Commence par"
69
+ ends_with: "Se termine par"
70
+ is_empty: "Est vide"
71
+ is_not_empty: "N'est pas vide"
72
+ range_ops:
73
+ between: "Entre"
74
+ number_ops:
75
+ eq: "Égal à"
76
+ neq: "Différent de"
77
+ gt: "Supérieur à"
78
+ gte: "Supérieur ou égal à"
79
+ lt: "Inférieur à"
80
+ lte: "Inférieur ou égal à"
81
+ date_ops:
82
+ "on": "Le"
83
+ before: "Avant"
84
+ after: "Après"
85
+
86
+ formatters:
87
+ ago: "il y a %{time}"
88
+ date:
89
+ short: "%d %b %Y"
90
+ long: "%d %B %Y"
91
+ time: "%H:%M"
92
+ datetime: "%d %b %Y %H:%M"
93
+ action: "Action"
94
+ boolean:
95
+ "true": "Oui"
96
+ "false": "Non"
97
+ duration:
98
+ short:
99
+ d: "%{count} j"
100
+ h: "%{count} h"
101
+ m: "%{count} min"
102
+ s: "%{count} s"
103
+ long:
104
+ d: { one: "%{count} jour", few: "%{count} jours", many: "%{count} jours", other: "%{count} jours" }
105
+ h: { one: "%{count} heure", few: "%{count} heures", many: "%{count} heures", other: "%{count} heures" }
106
+ m: { one: "%{count} minute", few: "%{count} minutes", many: "%{count} minutes", other: "%{count} minutes" }
107
+ s: { one: "%{count} seconde", few: "%{count} secondes", many: "%{count} secondes", other: "%{count} secondes" }
108
+
109
+ batch:
110
+ selected: "%{count} sélectionné(s)"
111
+ clear: "Effacer la sélection"
112
+ select_all: "Sélectionner toutes les lignes"
113
+ select_row: "Sélectionner la ligne"
114
+ select_all_matching: "Sélectionner les %{count} résultats"
115
+ truncated: "Seules les %{max} premières lignes sont sélectionnées"
116
+
117
+ search:
118
+ placeholder: "Rechercher..."
119
+ label: "Rechercher dans le tableau"
120
+
121
+ pagination:
122
+ summary_html: "Affichage de %{from} à %{to} sur %{total} résultats"
123
+ summary_no_total_html: "Affichage de %{from} à %{to}"
124
+ rows_per_page: "Lignes par page :"
125
+ previous: "Précédent"
126
+ next: "Suivant"
@@ -0,0 +1,126 @@
1
+ it:
2
+ infotable:
3
+ table:
4
+ buttons:
5
+ export_csv: "Esporta CSV"
6
+ filters: "Filtri"
7
+ exporting: "Esportazione..."
8
+ refresh: "Aggiorna"
9
+ columns: "Colonne"
10
+ sort_hint: "Clicca per ordinare, Maiusc+clic aggiunge una colonna all'ordinamento"
11
+ loading:
12
+ initial: "Caricamento dati..."
13
+ more_items: "Caricamento di altri elementi..."
14
+ all_loaded: "Tutti gli elementi sono stati caricati"
15
+ resize_column: "ridimensiona colonna"
16
+ empty_state:
17
+ title: "Nessun dato trovato"
18
+ description: "Aggiungi dei record per vederli qui."
19
+ filtered_title: "Nessuna riga corrisponde ai filtri"
20
+ filtered_description: "Rimuovi un filtro o cerca qualcos'altro."
21
+
22
+ drawer:
23
+ label: "Filtri e colonne"
24
+ panel_title:
25
+ customize_columns: "Personalizza colonne"
26
+ filters: "Filtri"
27
+ columns: "Colonne"
28
+ tabs:
29
+ filters: "Filtri"
30
+ columns: "Colonne"
31
+
32
+ columns:
33
+ instructions: "Trascina per riordinare, fissa le colonne e mostra/nascondi:"
34
+ pin:
35
+ left: "Fissa a sinistra"
36
+ right: "Fissa a destra"
37
+ actions:
38
+ select_all: "Seleziona tutto"
39
+ deselect_all: "Deseleziona tutto"
40
+ reset_to_defaults: "🔄 Ripristina predefiniti"
41
+
42
+ filters:
43
+ actions:
44
+ clear_all: "Cancella tutto"
45
+ apply_filters: "Applica filtri"
46
+ clear_filter: "Cancella questo filtro"
47
+ active:
48
+ search: "Ricerca: «%{query}»"
49
+ remove: "Rimuovi il filtro %{filter}"
50
+ clear_all: "Cancella tutti i filtri"
51
+ from: "Da"
52
+ to: "A"
53
+ min: "Min"
54
+ max: "Max"
55
+ enter_value: "Inserisci un valore..."
56
+ all: "Tutti"
57
+ multi_select_hint: "Tieni premuto Ctrl/Cmd per selezionarne più di uno"
58
+ options_truncated: "Mostrate le prime %{shown} opzioni su %{total}"
59
+ boolean:
60
+ "true": "Vero"
61
+ "false": "Falso"
62
+ empty: "Vuoto"
63
+ not_empty: "Non vuoto"
64
+ text_ops:
65
+ contains: "Contiene"
66
+ exact: "Corrispondenza esatta"
67
+ not_contain: "Non contiene"
68
+ starts_with: "Inizia con"
69
+ ends_with: "Finisce con"
70
+ is_empty: "È vuoto"
71
+ is_not_empty: "Non è vuoto"
72
+ range_ops:
73
+ between: "Tra"
74
+ number_ops:
75
+ eq: "Uguale a"
76
+ neq: "Diverso da"
77
+ gt: "Maggiore di"
78
+ gte: "Maggiore o uguale a"
79
+ lt: "Minore di"
80
+ lte: "Minore o uguale a"
81
+ date_ops:
82
+ "on": "Il"
83
+ before: "Prima del"
84
+ after: "Dopo il"
85
+
86
+ formatters:
87
+ ago: "%{time} fa"
88
+ date:
89
+ short: "%d %b %Y"
90
+ long: "%d %B %Y"
91
+ time: "%H:%M"
92
+ datetime: "%d %b %Y %H:%M"
93
+ action: "Azione"
94
+ boolean:
95
+ "true": "Sì"
96
+ "false": "No"
97
+ duration:
98
+ short:
99
+ d: "%{count} g"
100
+ h: "%{count} h"
101
+ m: "%{count} min"
102
+ s: "%{count} s"
103
+ long:
104
+ d: { one: "%{count} giorno", few: "%{count} giorni", many: "%{count} giorni", other: "%{count} giorni" }
105
+ h: { one: "%{count} ora", few: "%{count} ore", many: "%{count} ore", other: "%{count} ore" }
106
+ m: { one: "%{count} minuto", few: "%{count} minuti", many: "%{count} minuti", other: "%{count} minuti" }
107
+ s: { one: "%{count} secondo", few: "%{count} secondi", many: "%{count} secondi", other: "%{count} secondi" }
108
+
109
+ batch:
110
+ selected: "%{count} selezionati"
111
+ clear: "Cancella selezione"
112
+ select_all: "Seleziona tutte le righe"
113
+ select_row: "Seleziona riga"
114
+ select_all_matching: "Seleziona tutti i %{count} risultati"
115
+ truncated: "Sono selezionate solo le prime %{max} righe"
116
+
117
+ search:
118
+ placeholder: "Cerca..."
119
+ label: "Cerca nella tabella"
120
+
121
+ pagination:
122
+ summary_html: "Visualizzazione da %{from} a %{to} di %{total} risultati"
123
+ summary_no_total_html: "Visualizzazione da %{from} a %{to}"
124
+ rows_per_page: "Righe per pagina:"
125
+ previous: "Precedente"
126
+ next: "Successivo"
@@ -85,10 +85,26 @@ pl:
85
85
 
86
86
  formatters:
87
87
  ago: "%{time} temu"
88
+ date:
89
+ short: "%d %b %Y"
90
+ long: "%d %B %Y"
91
+ time: "%H:%M"
92
+ datetime: "%d %b %Y %H:%M"
88
93
  action: "Akcja"
89
94
  boolean:
90
95
  "true": "Tak"
91
96
  "false": "Nie"
97
+ duration:
98
+ short:
99
+ d: "%{count} d"
100
+ h: "%{count} godz."
101
+ m: "%{count} min"
102
+ s: "%{count} s"
103
+ long:
104
+ d: { one: "%{count} dzień", few: "%{count} dni", many: "%{count} dni", other: "%{count} dni" }
105
+ h: { one: "%{count} godzina", few: "%{count} godziny", many: "%{count} godzin", other: "%{count} godzin" }
106
+ m: { one: "%{count} minuta", few: "%{count} minuty", many: "%{count} minut", other: "%{count} minut" }
107
+ s: { one: "%{count} sekunda", few: "%{count} sekundy", many: "%{count} sekund", other: "%{count} sekund" }
92
108
 
93
109
  batch:
94
110
  selected: "Zaznaczono: %{count}"
@@ -103,10 +119,8 @@ pl:
103
119
  label: "Szukaj w tabeli"
104
120
 
105
121
  pagination:
106
- showing: "Wyświetlanie"
107
- to: "do"
108
- of: "z"
109
- results: "wyników"
122
+ summary_html: "Wyświetlanie %{from} do %{to} z %{total} wyników"
123
+ summary_no_total_html: "Wyświetlanie %{from} do %{to}"
110
124
  rows_per_page: "Wierszy na stronę:"
111
125
  previous: "Poprzednia"
112
126
  next: "Następna"
data/exe/infotable-mcp ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # MCP server (stdio) that lets an AI assistant create InfoTable tables in the host app:
3
+ # bundle exec infotable-mcp
4
+ # Run it from the Rails app's root, see "MCP server" in the README.
5
+ require "bundler/setup"
6
+
7
+ environment = File.expand_path("config/environment", Dir.pwd)
8
+ abort "infotable-mcp: run it from the root of a Rails app (no config/environment.rb in #{Dir.pwd})" unless File.exist?("#{environment}.rb")
9
+
10
+ require environment
11
+ require "infotable/mcp"
12
+
13
+ Infotable::Mcp::Server.run
@@ -14,9 +14,11 @@ Infotable.configure do |config|
14
14
  # Drawer width
15
15
  config.drawer_width = "26rem" # px, rem, em, vw or %
16
16
 
17
- # Controller the engine controllers inherit from. Use your app's controller so
18
- # authentication, locale, tenant scoping etc. also protect the tables:
19
- # config.parent_controller = "ApplicationController"
17
+ # SECURITY: tables are served at /infotable/tables/:name/{data,export,ids}. The engine
18
+ # controllers inherit from this controller, so authentication, locale, tenant scoping etc.
19
+ # of your app also protect the tables. With the default (ActionController::Base) nothing
20
+ # does: anyone can read and export every table that has no `authorize { ... }` block.
21
+ config.parent_controller = "ApplicationController"
20
22
 
21
23
  # Mirror search, filters, sort and page in the address bar (shareable links, Back button)
22
24
  # config.url_state = true
@@ -9,6 +9,14 @@ module Infotable
9
9
 
10
10
  class_option :only, type: :array, default: [], desc: "Only these columns"
11
11
  class_option :skip, type: :array, default: [], desc: "Leave these columns out"
12
+ class_option :per_page, type: :numeric, default: 25, desc: "Rows per page"
13
+ class_option :sort, type: :string, desc: "Default sort as column:direction, e.g. created_at:desc"
14
+ class_option :toolbar, type: :string, desc: "Toolbar mode: header or rail"
15
+ class_option :row_click, type: :boolean, default: false, desc: "Clicking a row opens its row_link"
16
+ class_option :infinite_scroll, type: :boolean, default: false, desc: "Infinite scroll instead of pages"
17
+ class_option :countless, type: :boolean, default: false, desc: "Skip the total count (big tables)"
18
+ class_option :checkbox, type: :boolean, default: false, desc: "Row selection column"
19
+ class_option :authorize, type: :string, desc: "Ruby expression over `controller` that decides who sees the table"
12
20
 
13
21
  # Attributes that must never end up in a table by accident
14
22
  SENSITIVE = /password|digest|token|secret|otp|encrypted/
@@ -82,9 +90,23 @@ module Infotable
82
90
  @model.reflect_on_all_associations(:belongs_to).map(&:name)
83
91
  end
84
92
 
93
+ # Table-level settings chosen with the options above, one DSL line each
94
+ def setting_lines
95
+ lines = []
96
+ lines << "toolbar :#{options[:toolbar]}" if options[:toolbar].present?
97
+ lines << "infinite_scroll true" if options[:infinite_scroll]
98
+ lines << "countless" if options[:countless]
99
+ lines << "checkbox_column" if options[:checkbox]
100
+ lines << "row_click" if options[:row_click]
101
+ lines
102
+ end
103
+
85
104
  def default_sort_line
86
105
  names = column_specs.map { _1[:name] }
87
- if names.include?("created_at")
106
+ if options[:sort].present?
107
+ column, direction = options[:sort].split(":")
108
+ "default_sort :#{column}, :#{direction == 'desc' ? 'desc' : 'asc'}"
109
+ elsif names.include?("created_at")
88
110
  "default_sort :created_at, :desc"
89
111
  elsif names.any?
90
112
  "default_sort :#{names.first}, :asc"
@@ -19,8 +19,15 @@ class <%= table_class_name %> < Infotable::Base
19
19
  <% end -%>
20
20
  <% end -%>
21
21
 
22
- per_page 25
22
+ per_page <%= options[:per_page] %>
23
23
  <% if default_sort_line %>
24
24
  <%= default_sort_line %>
25
25
  <% end -%>
26
+ <% setting_lines.each do |line| -%>
27
+ <%= line %>
28
+ <% end -%>
29
+ <% if options[:authorize].present? %>
30
+
31
+ authorize { |controller| <%= options[:authorize] %> }
32
+ <% end -%>
26
33
  end