rails_admin_next 1.0.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 (184) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +46 -0
  3. data/LICENSE.md +21 -0
  4. data/README.md +317 -0
  5. data/Rakefile +25 -0
  6. data/app/assets/javascripts/rails_admin/custom/ui.js +1 -0
  7. data/app/assets/stylesheets/rails_admin/framework.css +2375 -0
  8. data/app/assets/stylesheets/rails_admin/skin.css +472 -0
  9. data/app/assets/stylesheets/rails_admin/tokens.css +281 -0
  10. data/app/assets/stylesheets/rails_admin.css +47 -0
  11. data/app/controllers/rails_admin_next/application_controller.rb +98 -0
  12. data/app/controllers/rails_admin_next/main_controller.rb +185 -0
  13. data/app/helpers/rails_admin_next/application_helper.rb +254 -0
  14. data/app/helpers/rails_admin_next/form_builder.rb +173 -0
  15. data/app/helpers/rails_admin_next/main_helper.rb +63 -0
  16. data/app/views/layouts/rails_admin_next/_head.html.erb +29 -0
  17. data/app/views/layouts/rails_admin_next/_navigation.html.erb +18 -0
  18. data/app/views/layouts/rails_admin_next/_secondary_navigation.html.erb +27 -0
  19. data/app/views/layouts/rails_admin_next/_sidebar_navigation.html.erb +6 -0
  20. data/app/views/layouts/rails_admin_next/application.html.erb +42 -0
  21. data/app/views/layouts/rails_admin_next/content.html.erb +22 -0
  22. data/app/views/layouts/rails_admin_next/modal.js.erb +7 -0
  23. data/app/views/rails_admin_next/main/_dashboard_history.html.erb +46 -0
  24. data/app/views/rails_admin_next/main/_delete_notice.html.erb +36 -0
  25. data/app/views/rails_admin_next/main/_form_action_text.html.erb +2 -0
  26. data/app/views/rails_admin_next/main/_form_boolean.html.erb +15 -0
  27. data/app/views/rails_admin_next/main/_form_colorpicker.html.erb +6 -0
  28. data/app/views/rails_admin_next/main/_form_datetime.html.erb +14 -0
  29. data/app/views/rails_admin_next/main/_form_enumeration.html.erb +26 -0
  30. data/app/views/rails_admin_next/main/_form_field.html.erb +2 -0
  31. data/app/views/rails_admin_next/main/_form_file_upload.html.erb +18 -0
  32. data/app/views/rails_admin_next/main/_form_filtering_multiselect.html.erb +20 -0
  33. data/app/views/rails_admin_next/main/_form_filtering_select.html.erb +22 -0
  34. data/app/views/rails_admin_next/main/_form_multiple_file_upload.html.erb +21 -0
  35. data/app/views/rails_admin_next/main/_form_nested_many.html.erb +20 -0
  36. data/app/views/rails_admin_next/main/_form_nested_one.html.erb +19 -0
  37. data/app/views/rails_admin_next/main/_form_polymorphic_association.html.erb +24 -0
  38. data/app/views/rails_admin_next/main/_form_text.html.erb +2 -0
  39. data/app/views/rails_admin_next/main/_pagination.html.erb +54 -0
  40. data/app/views/rails_admin_next/main/_submit_buttons.html.erb +26 -0
  41. data/app/views/rails_admin_next/main/bulk_delete.html.erb +19 -0
  42. data/app/views/rails_admin_next/main/dashboard.html.erb +64 -0
  43. data/app/views/rails_admin_next/main/delete.html.erb +21 -0
  44. data/app/views/rails_admin_next/main/edit.html.erb +3 -0
  45. data/app/views/rails_admin_next/main/export.html.erb +149 -0
  46. data/app/views/rails_admin_next/main/history.html.erb +80 -0
  47. data/app/views/rails_admin_next/main/index.html.erb +186 -0
  48. data/app/views/rails_admin_next/main/new.html.erb +3 -0
  49. data/app/views/rails_admin_next/main/show.html.erb +30 -0
  50. data/config/brakeman.ignore +145 -0
  51. data/config/importmap.rails_admin.rb +29 -0
  52. data/config/initializers/active_record_extensions.rb +21 -0
  53. data/config/locales/rails_admin_next.en.yml +158 -0
  54. data/config/routes.rb +14 -0
  55. data/lib/generators/rails_admin_next/install_generator.rb +39 -0
  56. data/lib/generators/rails_admin_next/templates/initializer.erb +40 -0
  57. data/lib/generators/rails_admin_next/utils.rb +21 -0
  58. data/lib/rails_admin_next/abstract_model.rb +266 -0
  59. data/lib/rails_admin_next/adapters/active_record/association.rb +130 -0
  60. data/lib/rails_admin_next/adapters/active_record/object_extension.rb +13 -0
  61. data/lib/rails_admin_next/adapters/active_record/property.rb +58 -0
  62. data/lib/rails_admin_next/adapters/active_record.rb +371 -0
  63. data/lib/rails_admin_next/config/actions/base.rb +160 -0
  64. data/lib/rails_admin_next/config/actions/bulk_delete.rb +67 -0
  65. data/lib/rails_admin_next/config/actions/dashboard.rb +62 -0
  66. data/lib/rails_admin_next/config/actions/delete.rb +58 -0
  67. data/lib/rails_admin_next/config/actions/edit.rb +56 -0
  68. data/lib/rails_admin_next/config/actions/export.rb +47 -0
  69. data/lib/rails_admin_next/config/actions/history_index.rb +40 -0
  70. data/lib/rails_admin_next/config/actions/history_show.rb +40 -0
  71. data/lib/rails_admin_next/config/actions/index.rb +108 -0
  72. data/lib/rails_admin_next/config/actions/new.rb +69 -0
  73. data/lib/rails_admin_next/config/actions/show.rb +36 -0
  74. data/lib/rails_admin_next/config/actions/show_in_app.rb +37 -0
  75. data/lib/rails_admin_next/config/actions.rb +122 -0
  76. data/lib/rails_admin_next/config/configurable.rb +107 -0
  77. data/lib/rails_admin_next/config/const_load_suppressor.rb +78 -0
  78. data/lib/rails_admin_next/config/fields/association.rb +169 -0
  79. data/lib/rails_admin_next/config/fields/base.rb +391 -0
  80. data/lib/rails_admin_next/config/fields/collection_association.rb +90 -0
  81. data/lib/rails_admin_next/config/fields/factories/action_text.rb +14 -0
  82. data/lib/rails_admin_next/config/fields/factories/active_storage.rb +34 -0
  83. data/lib/rails_admin_next/config/fields/factories/association.rb +32 -0
  84. data/lib/rails_admin_next/config/fields/factories/encrypted_password.rb +28 -0
  85. data/lib/rails_admin_next/config/fields/factories/enum.rb +23 -0
  86. data/lib/rails_admin_next/config/fields/factories/password.rb +19 -0
  87. data/lib/rails_admin_next/config/fields/group.rb +77 -0
  88. data/lib/rails_admin_next/config/fields/singular_association.rb +62 -0
  89. data/lib/rails_admin_next/config/fields/types/action_text.rb +20 -0
  90. data/lib/rails_admin_next/config/fields/types/active_record_enum.rb +62 -0
  91. data/lib/rails_admin_next/config/fields/types/active_storage.rb +70 -0
  92. data/lib/rails_admin_next/config/fields/types/all.rb +32 -0
  93. data/lib/rails_admin_next/config/fields/types/belongs_to_association.rb +48 -0
  94. data/lib/rails_admin_next/config/fields/types/boolean.rb +70 -0
  95. data/lib/rails_admin_next/config/fields/types/citext.rb +15 -0
  96. data/lib/rails_admin_next/config/fields/types/color.rb +43 -0
  97. data/lib/rails_admin_next/config/fields/types/date.rb +38 -0
  98. data/lib/rails_admin_next/config/fields/types/datetime.rb +79 -0
  99. data/lib/rails_admin_next/config/fields/types/decimal.rb +23 -0
  100. data/lib/rails_admin_next/config/fields/types/enum.rb +52 -0
  101. data/lib/rails_admin_next/config/fields/types/file_upload.rb +87 -0
  102. data/lib/rails_admin_next/config/fields/types/float.rb +23 -0
  103. data/lib/rails_admin_next/config/fields/types/has_and_belongs_to_many_association.rb +16 -0
  104. data/lib/rails_admin_next/config/fields/types/has_many_association.rb +16 -0
  105. data/lib/rails_admin_next/config/fields/types/has_one_association.rb +35 -0
  106. data/lib/rails_admin_next/config/fields/types/hidden.rb +31 -0
  107. data/lib/rails_admin_next/config/fields/types/inet.rb +15 -0
  108. data/lib/rails_admin_next/config/fields/types/integer.rb +20 -0
  109. data/lib/rails_admin_next/config/fields/types/json.rb +37 -0
  110. data/lib/rails_admin_next/config/fields/types/multiple_active_storage.rb +82 -0
  111. data/lib/rails_admin_next/config/fields/types/multiple_file_upload.rb +134 -0
  112. data/lib/rails_admin_next/config/fields/types/numeric.rb +24 -0
  113. data/lib/rails_admin_next/config/fields/types/password.rb +45 -0
  114. data/lib/rails_admin_next/config/fields/types/polymorphic_association.rb +118 -0
  115. data/lib/rails_admin_next/config/fields/types/serialized.rb +28 -0
  116. data/lib/rails_admin_next/config/fields/types/string.rb +50 -0
  117. data/lib/rails_admin_next/config/fields/types/string_like.rb +25 -0
  118. data/lib/rails_admin_next/config/fields/types/text.rb +28 -0
  119. data/lib/rails_admin_next/config/fields/types/time.rb +39 -0
  120. data/lib/rails_admin_next/config/fields/types/timestamp.rb +16 -0
  121. data/lib/rails_admin_next/config/fields/types/uuid.rb +15 -0
  122. data/lib/rails_admin_next/config/fields/types.rb +29 -0
  123. data/lib/rails_admin_next/config/fields.rb +88 -0
  124. data/lib/rails_admin_next/config/groupable.rb +20 -0
  125. data/lib/rails_admin_next/config/has_description.rb +14 -0
  126. data/lib/rails_admin_next/config/has_fields.rb +144 -0
  127. data/lib/rails_admin_next/config/has_groups.rb +27 -0
  128. data/lib/rails_admin_next/config/hideable.rb +30 -0
  129. data/lib/rails_admin_next/config/inspectable.rb +39 -0
  130. data/lib/rails_admin_next/config/lazy_model.rb +74 -0
  131. data/lib/rails_admin_next/config/model.rb +126 -0
  132. data/lib/rails_admin_next/config/proxyable/proxy.rb +42 -0
  133. data/lib/rails_admin_next/config/proxyable.rb +26 -0
  134. data/lib/rails_admin_next/config/sections/base.rb +36 -0
  135. data/lib/rails_admin_next/config/sections/create.rb +13 -0
  136. data/lib/rails_admin_next/config/sections/edit.rb +13 -0
  137. data/lib/rails_admin_next/config/sections/export.rb +13 -0
  138. data/lib/rails_admin_next/config/sections/list.rb +63 -0
  139. data/lib/rails_admin_next/config/sections/modal.rb +12 -0
  140. data/lib/rails_admin_next/config/sections/nested.rb +12 -0
  141. data/lib/rails_admin_next/config/sections/show.rb +12 -0
  142. data/lib/rails_admin_next/config/sections/update.rb +12 -0
  143. data/lib/rails_admin_next/config/sections.rb +39 -0
  144. data/lib/rails_admin_next/config.rb +436 -0
  145. data/lib/rails_admin_next/engine.rb +91 -0
  146. data/lib/rails_admin_next/extension.rb +35 -0
  147. data/lib/rails_admin_next/extensions/cancancan/authorization_adapter.rb +90 -0
  148. data/lib/rails_admin_next/extensions/cancancan.rb +5 -0
  149. data/lib/rails_admin_next/extensions/controller_extension.rb +8 -0
  150. data/lib/rails_admin_next/extensions/paper_trail/auditing_adapter.rb +192 -0
  151. data/lib/rails_admin_next/extensions/paper_trail.rb +5 -0
  152. data/lib/rails_admin_next/extensions/pundit/authorization_adapter.rb +72 -0
  153. data/lib/rails_admin_next/extensions/pundit.rb +5 -0
  154. data/lib/rails_admin_next/extensions/url_for_extension.rb +15 -0
  155. data/lib/rails_admin_next/icons.rb +143 -0
  156. data/lib/rails_admin_next/support/composite_keys_serializer.rb +15 -0
  157. data/lib/rails_admin_next/support/csv_converter.rb +100 -0
  158. data/lib/rails_admin_next/support/hash_helper.rb +31 -0
  159. data/lib/rails_admin_next/support/paginated_collection.rb +79 -0
  160. data/lib/rails_admin_next/version.rb +17 -0
  161. data/lib/rails_admin_next.rb +72 -0
  162. data/lib/tasks/rails_admin.rake +40 -0
  163. data/src/rails_admin/application.js +15 -0
  164. data/src/rails_admin/base.js +12 -0
  165. data/src/rails_admin/controllers/alert_controller.js +28 -0
  166. data/src/rails_admin/controllers/collapse_controller.js +16 -0
  167. data/src/rails_admin/controllers/dropdown_controller.js +110 -0
  168. data/src/rails_admin/controllers/feedback_controller.js +73 -0
  169. data/src/rails_admin/controllers/filter_box_controller.js +346 -0
  170. data/src/rails_admin/controllers/filtering_multiselect_controller.js +386 -0
  171. data/src/rails_admin/controllers/filtering_select_controller.js +509 -0
  172. data/src/rails_admin/controllers/index.js +31 -0
  173. data/src/rails_admin/controllers/modal_controller.js +142 -0
  174. data/src/rails_admin/controllers/nested_form_controller.js +117 -0
  175. data/src/rails_admin/controllers/polymorphic_controller.js +26 -0
  176. data/src/rails_admin/controllers/remote_form_controller.js +173 -0
  177. data/src/rails_admin/controllers/sidescroll_controller.js +23 -0
  178. data/src/rails_admin/dom-ready.js +20 -0
  179. data/src/rails_admin/dom.js +19 -0
  180. data/src/rails_admin/i18n.js +20 -0
  181. data/src/rails_admin/icons.js +64 -0
  182. data/src/rails_admin/interactions.js +221 -0
  183. data/src/rails_admin/select_query.js +65 -0
  184. metadata +346 -0
@@ -0,0 +1,221 @@
1
+ // Document-level page interactions: global, delegated behaviors with no single
2
+ // host element (a select-all in the table head, the bulk-action menu in the
3
+ // navbar, sortable column headers, the export field pickers), so they stay
4
+ // plain delegated DOM listeners rather than per-element Stimulus controllers.
5
+ // Field/widget behaviors (datetime, file upload, rich text, the inline-edit
6
+ // modal) are Stimulus controllers instead.
7
+ //
8
+ // Registered once at import time — the document survives Turbo Drive navigation,
9
+ // so delegated listeners keep working across visits without re-binding.
10
+
11
+ // --- Loading indicator -------------------------------------------------------
12
+ document.addEventListener("turbo:click", () => {
13
+ const loading = document.getElementById("loading");
14
+ if (loading) loading.style.display = "";
15
+ });
16
+ document.addEventListener("turbo:before-render", () => {
17
+ const loading = document.getElementById("loading");
18
+ if (loading) loading.style.display = "none";
19
+ });
20
+
21
+ // --- Forms: preserve the clicked submit button ------------------------------
22
+ // Append a hidden input carrying the pressed button's name/value, and skip
23
+ // constraint validation for a [formnovalidate] button. The submit event's
24
+ // `submitter` is not reliably set for synthetic (script-driven) clicks, so the
25
+ // form body would otherwise lose which button was pressed (Save vs Cancel vs
26
+ // Save and edit) — and a Cancel could be blocked by an unrelated invalid field.
27
+ // Clicking clears out any hidden input left behind by an earlier click whose
28
+ // submit was blocked by native validation, so a stale button param can't ride
29
+ // along on the next, different submit.
30
+ document.addEventListener("click", (event) => {
31
+ const button = event.target.closest('button[name][type="submit"]');
32
+ if (!button) return;
33
+ const form = button.form || button.closest("form");
34
+ if (!form) return;
35
+ form
36
+ .querySelectorAll("input[data-submit-button-param]")
37
+ .forEach((input) => input.remove());
38
+ const hidden = document.createElement("input");
39
+ hidden.type = "hidden";
40
+ hidden.name = button.name;
41
+ hidden.value = button.value;
42
+ hidden.dataset.submitButtonParam = "true";
43
+ form.appendChild(hidden);
44
+ if (button.hasAttribute("formnovalidate"))
45
+ form.setAttribute("novalidate", "true");
46
+ });
47
+
48
+ // --- Index list: select-all bulk checkboxes ----------------------------------
49
+ document.addEventListener("change", (event) => {
50
+ if (!event.target.matches("#list input.toggle")) return;
51
+ document
52
+ .querySelectorAll("#list [name='bulk_ids[]']")
53
+ .forEach((checkbox) => (checkbox.checked = event.target.checked));
54
+ });
55
+
56
+ // --- Index list: sortable column headers -------------------------------------
57
+ document.addEventListener("click", (event) => {
58
+ const header = event.target.closest("th.header");
59
+ if (!header) return;
60
+ event.preventDefault();
61
+ if (header.dataset.href) window.Turbo.visit(header.dataset.href);
62
+ });
63
+
64
+ // --- Index list: bulk-action menu links --------------------------------------
65
+ document.addEventListener("click", (event) => {
66
+ const link = event.target.closest(".bulk-link");
67
+ if (!link) return;
68
+ event.preventDefault();
69
+ const action = document.getElementById("bulk_action");
70
+ if (action) action.value = link.dataset.action;
71
+ // Native submit (full navigation): the bulk action renders its confirmation
72
+ // page with a 200, which Turbo's form handling would reject as "must
73
+ // redirect".
74
+ document.getElementById("bulk_form")?.submit();
75
+ });
76
+
77
+ // --- Index list: reset filters -----------------------------------------------
78
+ document.addEventListener("click", (event) => {
79
+ const button = event.target.closest("#remove_filter");
80
+ if (!button) return;
81
+ event.preventDefault();
82
+ // Emptying the box is the whole state change: the hr.filters_box divider
83
+ // derives its visibility from the .filter rows via :has() CSS (skin.css).
84
+ document.getElementById("filters_box")?.replaceChildren();
85
+ const form = button.closest("form");
86
+ const search = button.parentNode.querySelector("input[type='search']");
87
+ if (search) search.value = "";
88
+ form?.requestSubmit();
89
+ });
90
+
91
+ // --- Export: select-all / reverse-selection ----------------------------------
92
+ document.addEventListener("change", (event) => {
93
+ if (!event.target.matches("#fields_to_export #check_all")) return;
94
+ document
95
+ .querySelectorAll("#fields_to_export label input")
96
+ .forEach((input) => (input.checked = event.target.checked));
97
+ });
98
+ document.addEventListener("click", (event) => {
99
+ const card = event.target.closest("#fields_to_export .reverse-selection");
100
+ if (!card) return;
101
+ card
102
+ .closest(".control-group")
103
+ .querySelectorAll(".controls input")
104
+ .forEach((input) => input.click());
105
+ });
106
+
107
+ // --- File upload: inline image preview + delete toggle -----------------------
108
+ function isImage(filename) {
109
+ return ["gif", "png", "jpg", "jpeg", "bmp"].includes(
110
+ filename.split(".").pop().toLowerCase()
111
+ );
112
+ }
113
+
114
+ // Single upload: replace/insert one preview image on change.
115
+ document.addEventListener("change", (event) => {
116
+ const input = event.target;
117
+ if (!input.matches("[data-fileupload]")) return;
118
+ const parent = input.parentNode;
119
+ let preview = parent.querySelector(":scope > img.preview");
120
+ if (!preview) {
121
+ preview = document.createElement("img");
122
+ preview.className = "preview img-thumbnail";
123
+ parent.prepend(preview);
124
+ parent
125
+ .querySelectorAll("img:not(.preview)")
126
+ .forEach((img) => (img.style.display = "none"));
127
+ }
128
+ if (input.files && input.files[0] && isImage(input.value)) {
129
+ const file = input.files[0];
130
+ const reader = new FileReader();
131
+ reader.onload = (e) => {
132
+ if (input.files[0] === file) preview.src = e.target.result;
133
+ };
134
+ reader.readAsDataURL(file);
135
+ preview.style.display = "";
136
+ } else {
137
+ preview.style.display = "none";
138
+ }
139
+ });
140
+
141
+ // Multiple upload: render one preview per selected image.
142
+ document.addEventListener("change", (event) => {
143
+ const input = event.target;
144
+ if (!input.matches("[data-multiple-fileupload]")) return;
145
+ const parent = input.parentNode;
146
+ parent.querySelectorAll(":scope > .preview").forEach((node) => node.remove());
147
+ Array.from(input.files).forEach((file) => {
148
+ if (!isImage(file.name)) return;
149
+ const image = document.createElement("img");
150
+ image.className = "preview img-thumbnail";
151
+ const reader = new FileReader();
152
+ reader.onload = (e) => (image.src = e.target.result);
153
+ reader.readAsDataURL(file);
154
+ const wrapper = document.createElement("div");
155
+ wrapper.className = "preview";
156
+ wrapper.appendChild(image);
157
+ parent.appendChild(wrapper);
158
+ });
159
+ });
160
+
161
+ // "Delete file" button: toggle the hidden delete/keep checkbox and hide the row.
162
+ document.addEventListener("click", (event) => {
163
+ const button = event.target.closest(".btn-remove-image");
164
+ if (!button) return;
165
+ event.preventDefault();
166
+ button.parentNode.querySelector("input[type=checkbox]")?.click();
167
+ const toggle =
168
+ button.closest(".toggle") || button.parentNode.querySelector(".toggle");
169
+ if (toggle)
170
+ toggle.style.display = toggle.style.display === "none" ? "" : "none";
171
+ button.classList.toggle("btn-danger");
172
+ button.classList.toggle("btn-info");
173
+ });
174
+
175
+ // --- Sidebar groups: persist collapsed <details> across Turbo visits ----------
176
+ // The sidebar disclosure groups are native <details data-collapse-key> elements
177
+ // the server always renders open. Before Turbo swaps bodies, copy each keyed
178
+ // group's collapsed state onto its counterpart in the new body, so any number
179
+ // of collapsed groups survive navigation regardless of group order.
180
+ document.addEventListener("turbo:before-render", (event) => {
181
+ document
182
+ .querySelectorAll("details[data-collapse-key]:not([open])")
183
+ .forEach((details) => {
184
+ event.detail.newBody
185
+ .querySelector(
186
+ `details[data-collapse-key="${details.dataset.collapseKey}"]`
187
+ )
188
+ ?.removeAttribute("open");
189
+ });
190
+ });
191
+
192
+ // --- Form field groups: collapse on legend click -----------------------------
193
+ function siblingControlGroups(legend) {
194
+ return Array.from(legend.parentNode.children).filter(
195
+ (node) => node !== legend && node.classList.contains("control-group")
196
+ );
197
+ }
198
+
199
+ document.addEventListener("click", (event) => {
200
+ const legend = event.target.closest("form legend");
201
+ if (!legend) return;
202
+ // A single chevron-down SVG; the `collapsed` class rotates it to point right.
203
+ const chevron = legend.querySelector('svg[data-icon="collapse"]');
204
+ if (!chevron) return;
205
+ const collapsing = !chevron.classList.contains("collapsed");
206
+ siblingControlGroups(legend).forEach(
207
+ (group) => (group.style.display = collapsing ? "none" : "")
208
+ );
209
+ chevron.classList.toggle("collapsed");
210
+ });
211
+
212
+ // Groups whose legend renders collapsed start hidden.
213
+ document.addEventListener("rails_admin.dom_ready", () => {
214
+ document.querySelectorAll("form.main legend").forEach((legend) => {
215
+ if (legend.querySelector('svg[data-icon="collapse"].collapsed')) {
216
+ siblingControlGroups(legend).forEach(
217
+ (group) => (group.style.display = "none")
218
+ );
219
+ }
220
+ });
221
+ });
@@ -0,0 +1,65 @@
1
+ // Shared by the filtering-select and filtering-multiselect Stimulus controllers:
2
+ // createQuery/scopeBy logic for building a (possibly scoped) remote query.
3
+
4
+ // Builds the remote query for a (possibly dynamically-scoped) association select.
5
+ // `scopeBy` maps a sibling field name -> the query key it constrains; the sibling's
6
+ // current value scopes the candidate list.
7
+ export function createScopedQuery(scopeBy, term) {
8
+ if (!scopeBy || Object.keys(scopeBy).length === 0) {
9
+ return { query: term };
10
+ }
11
+
12
+ const f = {};
13
+ for (const field in scopeBy) {
14
+ const targetField = scopeBy[field];
15
+ const sibling = document.querySelector(`[name$="[${field}]"]`);
16
+ const value = sibling ? sibling.value : "";
17
+ (f[targetField] ||= []).push(
18
+ value ? { o: "is", v: value } : { o: "_blank" }
19
+ );
20
+ }
21
+ return { query: term, f };
22
+ }
23
+
24
+ // Rails-style nested query string: { f: { team: [{ o: "is", v: 5 }] } } ->
25
+ // "f[team][0][o]=is&f[team][0][v]=5", matching the bracket notation Rails'
26
+ // param parser expects for nested params.
27
+ export function toQueryString(obj, prefix) {
28
+ const parts = [];
29
+ for (const key in obj) {
30
+ const value = obj[key];
31
+ const name = prefix ? `${prefix}[${key}]` : key;
32
+ if (value !== null && value !== undefined && typeof value === "object") {
33
+ const nested = toQueryString(value, name);
34
+ if (nested) parts.push(nested);
35
+ } else {
36
+ parts.push(
37
+ `${encodeURIComponent(name)}=${encodeURIComponent(value ?? "")}`
38
+ );
39
+ }
40
+ }
41
+ return parts.join("&");
42
+ }
43
+
44
+ // Escape a user-typed term for use in a case-insensitive RegExp.
45
+ export function escapeRegex(value) {
46
+ return String(value).replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
47
+ }
48
+
49
+ // Shared CSRF-token + JSON-fetch boilerplate for the filtering-select and
50
+ // filtering-multiselect remote (xhr) query paths. Callers keep their own
51
+ // requestId/AbortController bookkeeping and pass the controller's `signal`.
52
+ export function fetchJson(url, { signal } = {}) {
53
+ const token = document.querySelector('meta[name="csrf-token"]')?.content;
54
+ return fetch(url, {
55
+ headers: {
56
+ Accept: "application/json",
57
+ ...(token ? { "X-CSRF-Token": token } : {}),
58
+ },
59
+ credentials: "same-origin",
60
+ signal,
61
+ }).then((response) => {
62
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
63
+ return response.json();
64
+ });
65
+ }
metadata ADDED
@@ -0,0 +1,346 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_admin_next
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel López Prat
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: csv
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: geared_pagination
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: importmap-rails
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: propshaft
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '1.2'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '1.2'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rails
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '8.1'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '8.1'
82
+ - !ruby/object:Gem::Dependency
83
+ name: stimulus-rails
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.3'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.3'
96
+ - !ruby/object:Gem::Dependency
97
+ name: turbo-rails
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '1.0'
103
+ - - "<"
104
+ - !ruby/object:Gem::Version
105
+ version: '3'
106
+ type: :runtime
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '1.0'
113
+ - - "<"
114
+ - !ruby/object:Gem::Version
115
+ version: '3'
116
+ - !ruby/object:Gem::Dependency
117
+ name: bundler
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '1.0'
123
+ type: :development
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '1.0'
130
+ description: A Rails engine that auto-generates an easy-to-use admin interface for
131
+ your ActiveRecord data. A modernized fork of RailsAdmin, originally created by Erik
132
+ Michaels-Ober, Bogdan Gaza, and contributors.
133
+ email:
134
+ - daniel@6temes.cat
135
+ executables: []
136
+ extensions: []
137
+ extra_rdoc_files: []
138
+ files:
139
+ - Gemfile
140
+ - LICENSE.md
141
+ - README.md
142
+ - Rakefile
143
+ - app/assets/javascripts/rails_admin/custom/ui.js
144
+ - app/assets/stylesheets/rails_admin.css
145
+ - app/assets/stylesheets/rails_admin/framework.css
146
+ - app/assets/stylesheets/rails_admin/skin.css
147
+ - app/assets/stylesheets/rails_admin/tokens.css
148
+ - app/controllers/rails_admin_next/application_controller.rb
149
+ - app/controllers/rails_admin_next/main_controller.rb
150
+ - app/helpers/rails_admin_next/application_helper.rb
151
+ - app/helpers/rails_admin_next/form_builder.rb
152
+ - app/helpers/rails_admin_next/main_helper.rb
153
+ - app/views/layouts/rails_admin_next/_head.html.erb
154
+ - app/views/layouts/rails_admin_next/_navigation.html.erb
155
+ - app/views/layouts/rails_admin_next/_secondary_navigation.html.erb
156
+ - app/views/layouts/rails_admin_next/_sidebar_navigation.html.erb
157
+ - app/views/layouts/rails_admin_next/application.html.erb
158
+ - app/views/layouts/rails_admin_next/content.html.erb
159
+ - app/views/layouts/rails_admin_next/modal.js.erb
160
+ - app/views/rails_admin_next/main/_dashboard_history.html.erb
161
+ - app/views/rails_admin_next/main/_delete_notice.html.erb
162
+ - app/views/rails_admin_next/main/_form_action_text.html.erb
163
+ - app/views/rails_admin_next/main/_form_boolean.html.erb
164
+ - app/views/rails_admin_next/main/_form_colorpicker.html.erb
165
+ - app/views/rails_admin_next/main/_form_datetime.html.erb
166
+ - app/views/rails_admin_next/main/_form_enumeration.html.erb
167
+ - app/views/rails_admin_next/main/_form_field.html.erb
168
+ - app/views/rails_admin_next/main/_form_file_upload.html.erb
169
+ - app/views/rails_admin_next/main/_form_filtering_multiselect.html.erb
170
+ - app/views/rails_admin_next/main/_form_filtering_select.html.erb
171
+ - app/views/rails_admin_next/main/_form_multiple_file_upload.html.erb
172
+ - app/views/rails_admin_next/main/_form_nested_many.html.erb
173
+ - app/views/rails_admin_next/main/_form_nested_one.html.erb
174
+ - app/views/rails_admin_next/main/_form_polymorphic_association.html.erb
175
+ - app/views/rails_admin_next/main/_form_text.html.erb
176
+ - app/views/rails_admin_next/main/_pagination.html.erb
177
+ - app/views/rails_admin_next/main/_submit_buttons.html.erb
178
+ - app/views/rails_admin_next/main/bulk_delete.html.erb
179
+ - app/views/rails_admin_next/main/dashboard.html.erb
180
+ - app/views/rails_admin_next/main/delete.html.erb
181
+ - app/views/rails_admin_next/main/edit.html.erb
182
+ - app/views/rails_admin_next/main/export.html.erb
183
+ - app/views/rails_admin_next/main/history.html.erb
184
+ - app/views/rails_admin_next/main/index.html.erb
185
+ - app/views/rails_admin_next/main/new.html.erb
186
+ - app/views/rails_admin_next/main/show.html.erb
187
+ - config/brakeman.ignore
188
+ - config/importmap.rails_admin.rb
189
+ - config/initializers/active_record_extensions.rb
190
+ - config/locales/rails_admin_next.en.yml
191
+ - config/routes.rb
192
+ - lib/generators/rails_admin_next/install_generator.rb
193
+ - lib/generators/rails_admin_next/templates/initializer.erb
194
+ - lib/generators/rails_admin_next/utils.rb
195
+ - lib/rails_admin_next.rb
196
+ - lib/rails_admin_next/abstract_model.rb
197
+ - lib/rails_admin_next/adapters/active_record.rb
198
+ - lib/rails_admin_next/adapters/active_record/association.rb
199
+ - lib/rails_admin_next/adapters/active_record/object_extension.rb
200
+ - lib/rails_admin_next/adapters/active_record/property.rb
201
+ - lib/rails_admin_next/config.rb
202
+ - lib/rails_admin_next/config/actions.rb
203
+ - lib/rails_admin_next/config/actions/base.rb
204
+ - lib/rails_admin_next/config/actions/bulk_delete.rb
205
+ - lib/rails_admin_next/config/actions/dashboard.rb
206
+ - lib/rails_admin_next/config/actions/delete.rb
207
+ - lib/rails_admin_next/config/actions/edit.rb
208
+ - lib/rails_admin_next/config/actions/export.rb
209
+ - lib/rails_admin_next/config/actions/history_index.rb
210
+ - lib/rails_admin_next/config/actions/history_show.rb
211
+ - lib/rails_admin_next/config/actions/index.rb
212
+ - lib/rails_admin_next/config/actions/new.rb
213
+ - lib/rails_admin_next/config/actions/show.rb
214
+ - lib/rails_admin_next/config/actions/show_in_app.rb
215
+ - lib/rails_admin_next/config/configurable.rb
216
+ - lib/rails_admin_next/config/const_load_suppressor.rb
217
+ - lib/rails_admin_next/config/fields.rb
218
+ - lib/rails_admin_next/config/fields/association.rb
219
+ - lib/rails_admin_next/config/fields/base.rb
220
+ - lib/rails_admin_next/config/fields/collection_association.rb
221
+ - lib/rails_admin_next/config/fields/factories/action_text.rb
222
+ - lib/rails_admin_next/config/fields/factories/active_storage.rb
223
+ - lib/rails_admin_next/config/fields/factories/association.rb
224
+ - lib/rails_admin_next/config/fields/factories/encrypted_password.rb
225
+ - lib/rails_admin_next/config/fields/factories/enum.rb
226
+ - lib/rails_admin_next/config/fields/factories/password.rb
227
+ - lib/rails_admin_next/config/fields/group.rb
228
+ - lib/rails_admin_next/config/fields/singular_association.rb
229
+ - lib/rails_admin_next/config/fields/types.rb
230
+ - lib/rails_admin_next/config/fields/types/action_text.rb
231
+ - lib/rails_admin_next/config/fields/types/active_record_enum.rb
232
+ - lib/rails_admin_next/config/fields/types/active_storage.rb
233
+ - lib/rails_admin_next/config/fields/types/all.rb
234
+ - lib/rails_admin_next/config/fields/types/belongs_to_association.rb
235
+ - lib/rails_admin_next/config/fields/types/boolean.rb
236
+ - lib/rails_admin_next/config/fields/types/citext.rb
237
+ - lib/rails_admin_next/config/fields/types/color.rb
238
+ - lib/rails_admin_next/config/fields/types/date.rb
239
+ - lib/rails_admin_next/config/fields/types/datetime.rb
240
+ - lib/rails_admin_next/config/fields/types/decimal.rb
241
+ - lib/rails_admin_next/config/fields/types/enum.rb
242
+ - lib/rails_admin_next/config/fields/types/file_upload.rb
243
+ - lib/rails_admin_next/config/fields/types/float.rb
244
+ - lib/rails_admin_next/config/fields/types/has_and_belongs_to_many_association.rb
245
+ - lib/rails_admin_next/config/fields/types/has_many_association.rb
246
+ - lib/rails_admin_next/config/fields/types/has_one_association.rb
247
+ - lib/rails_admin_next/config/fields/types/hidden.rb
248
+ - lib/rails_admin_next/config/fields/types/inet.rb
249
+ - lib/rails_admin_next/config/fields/types/integer.rb
250
+ - lib/rails_admin_next/config/fields/types/json.rb
251
+ - lib/rails_admin_next/config/fields/types/multiple_active_storage.rb
252
+ - lib/rails_admin_next/config/fields/types/multiple_file_upload.rb
253
+ - lib/rails_admin_next/config/fields/types/numeric.rb
254
+ - lib/rails_admin_next/config/fields/types/password.rb
255
+ - lib/rails_admin_next/config/fields/types/polymorphic_association.rb
256
+ - lib/rails_admin_next/config/fields/types/serialized.rb
257
+ - lib/rails_admin_next/config/fields/types/string.rb
258
+ - lib/rails_admin_next/config/fields/types/string_like.rb
259
+ - lib/rails_admin_next/config/fields/types/text.rb
260
+ - lib/rails_admin_next/config/fields/types/time.rb
261
+ - lib/rails_admin_next/config/fields/types/timestamp.rb
262
+ - lib/rails_admin_next/config/fields/types/uuid.rb
263
+ - lib/rails_admin_next/config/groupable.rb
264
+ - lib/rails_admin_next/config/has_description.rb
265
+ - lib/rails_admin_next/config/has_fields.rb
266
+ - lib/rails_admin_next/config/has_groups.rb
267
+ - lib/rails_admin_next/config/hideable.rb
268
+ - lib/rails_admin_next/config/inspectable.rb
269
+ - lib/rails_admin_next/config/lazy_model.rb
270
+ - lib/rails_admin_next/config/model.rb
271
+ - lib/rails_admin_next/config/proxyable.rb
272
+ - lib/rails_admin_next/config/proxyable/proxy.rb
273
+ - lib/rails_admin_next/config/sections.rb
274
+ - lib/rails_admin_next/config/sections/base.rb
275
+ - lib/rails_admin_next/config/sections/create.rb
276
+ - lib/rails_admin_next/config/sections/edit.rb
277
+ - lib/rails_admin_next/config/sections/export.rb
278
+ - lib/rails_admin_next/config/sections/list.rb
279
+ - lib/rails_admin_next/config/sections/modal.rb
280
+ - lib/rails_admin_next/config/sections/nested.rb
281
+ - lib/rails_admin_next/config/sections/show.rb
282
+ - lib/rails_admin_next/config/sections/update.rb
283
+ - lib/rails_admin_next/engine.rb
284
+ - lib/rails_admin_next/extension.rb
285
+ - lib/rails_admin_next/extensions/cancancan.rb
286
+ - lib/rails_admin_next/extensions/cancancan/authorization_adapter.rb
287
+ - lib/rails_admin_next/extensions/controller_extension.rb
288
+ - lib/rails_admin_next/extensions/paper_trail.rb
289
+ - lib/rails_admin_next/extensions/paper_trail/auditing_adapter.rb
290
+ - lib/rails_admin_next/extensions/pundit.rb
291
+ - lib/rails_admin_next/extensions/pundit/authorization_adapter.rb
292
+ - lib/rails_admin_next/extensions/url_for_extension.rb
293
+ - lib/rails_admin_next/icons.rb
294
+ - lib/rails_admin_next/support/composite_keys_serializer.rb
295
+ - lib/rails_admin_next/support/csv_converter.rb
296
+ - lib/rails_admin_next/support/hash_helper.rb
297
+ - lib/rails_admin_next/support/paginated_collection.rb
298
+ - lib/rails_admin_next/version.rb
299
+ - lib/tasks/rails_admin.rake
300
+ - src/rails_admin/application.js
301
+ - src/rails_admin/base.js
302
+ - src/rails_admin/controllers/alert_controller.js
303
+ - src/rails_admin/controllers/collapse_controller.js
304
+ - src/rails_admin/controllers/dropdown_controller.js
305
+ - src/rails_admin/controllers/feedback_controller.js
306
+ - src/rails_admin/controllers/filter_box_controller.js
307
+ - src/rails_admin/controllers/filtering_multiselect_controller.js
308
+ - src/rails_admin/controllers/filtering_select_controller.js
309
+ - src/rails_admin/controllers/index.js
310
+ - src/rails_admin/controllers/modal_controller.js
311
+ - src/rails_admin/controllers/nested_form_controller.js
312
+ - src/rails_admin/controllers/polymorphic_controller.js
313
+ - src/rails_admin/controllers/remote_form_controller.js
314
+ - src/rails_admin/controllers/sidescroll_controller.js
315
+ - src/rails_admin/dom-ready.js
316
+ - src/rails_admin/dom.js
317
+ - src/rails_admin/i18n.js
318
+ - src/rails_admin/icons.js
319
+ - src/rails_admin/interactions.js
320
+ - src/rails_admin/select_query.js
321
+ homepage: https://github.com/6temes/rails_admin_next
322
+ licenses:
323
+ - MIT
324
+ metadata:
325
+ bug_tracker_uri: https://github.com/6temes/rails_admin_next/issues
326
+ changelog_uri: https://github.com/6temes/rails_admin_next/releases
327
+ rubygems_mfa_required: 'true'
328
+ source_code_uri: https://github.com/6temes/rails_admin_next
329
+ rdoc_options: []
330
+ require_paths:
331
+ - lib
332
+ required_ruby_version: !ruby/object:Gem::Requirement
333
+ requirements:
334
+ - - ">="
335
+ - !ruby/object:Gem::Version
336
+ version: 4.0.5
337
+ required_rubygems_version: !ruby/object:Gem::Requirement
338
+ requirements:
339
+ - - ">="
340
+ - !ruby/object:Gem::Version
341
+ version: 1.8.11
342
+ requirements: []
343
+ rubygems_version: 4.0.10
344
+ specification_version: 4
345
+ summary: Admin for Rails
346
+ test_files: []