admin_suite 0.5.0 → 0.6.1
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/.gitignore +7 -0
- data/CHANGELOG.md +69 -11
- data/CONTRIBUTING.md +9 -4
- data/README.md +21 -5
- data/app/controllers/admin_suite/application_controller.rb +12 -11
- data/app/controllers/admin_suite/mcp_controller.rb +36 -0
- data/app/controllers/admin_suite/resources_controller.rb +7 -78
- data/app/views/admin_suite/resources/index.html.erb +1 -0
- data/config/routes.rb +5 -0
- data/lib/admin/base/resource.rb +7 -29
- data/lib/admin_suite/auth/host_user.rb +42 -0
- data/lib/admin_suite/auth/strategy.rb +1 -1
- data/lib/admin_suite/auth.rb +15 -0
- data/lib/admin_suite/authorization_context.rb +28 -0
- data/lib/admin_suite/configuration.rb +56 -2
- data/lib/admin_suite/mcp/authorization.rb +68 -0
- data/lib/admin_suite/mcp/serializer.rb +138 -0
- data/lib/admin_suite/mcp/tools/aggregate.rb +55 -0
- data/lib/admin_suite/mcp/tools/describe_resources.rb +63 -0
- data/lib/admin_suite/mcp/tools/get_record.rb +41 -0
- data/lib/admin_suite/mcp/tools/list_records.rb +67 -0
- data/lib/admin_suite/mcp.rb +53 -0
- data/lib/admin_suite/query.rb +71 -0
- data/lib/admin_suite/ui/show_value_formatter.rb +2 -2
- data/lib/admin_suite/version.rb +1 -1
- data/lib/admin_suite.rb +14 -9
- data/lib/generators/admin_suite/install/templates/admin_suite.rb +5 -2
- data/test/controllers/resources_controller_test.rb +19 -13
- data/test/integration/authentication_test.rb +10 -0
- data/test/integration/authorization_test.rb +20 -3
- data/test/integration/index_query_characterization_test.rb +229 -0
- data/test/integration/mcp_aggregate_test.rb +44 -0
- data/test/integration/mcp_authorization_test.rb +102 -0
- data/test/integration/mcp_endpoint_test.rb +89 -0
- data/test/integration/mcp_get_record_test.rb +62 -0
- data/test/integration/mcp_instrumentation_test.rb +107 -0
- data/test/integration/mcp_list_records_test.rb +75 -0
- data/test/integration/mcp_parity_test.rb +155 -0
- data/test/integration/mcp_release_test.rb +131 -0
- data/test/integration/read_only_resource_test.rb +128 -2
- data/test/integration/searchable_select_search_test.rb +5 -4
- data/test/lib/auth_host_user_test.rb +52 -0
- data/test/lib/auth_http_basic_test.rb +10 -0
- data/test/lib/auth_test.rb +20 -3
- data/test/lib/authorization_context_test.rb +127 -0
- data/test/lib/engine_defaults_test.rb +1 -2
- data/test/lib/mcp_serializer_test.rb +107 -0
- data/test/lib/query_test.rb +91 -0
- data/test/lib/removed_deprecations_test.rb +16 -0
- data/test/publish_workflow_test.rb +63 -0
- data/test/test_helper.rb +26 -0
- metadata +42 -5
- data/lib/admin_suite/renderers/legacy_gleania.rb +0 -232
- data/test/lib/legacy_renderer_deprecation_test.rb +0 -42
- data/test/lib/resource_exportable_deprecation_test.rb +0 -47
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: admin_suite
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- TechWright Labs
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -50,6 +50,20 @@ dependencies:
|
|
|
50
50
|
- - "<"
|
|
51
51
|
- !ruby/object:Gem::Version
|
|
52
52
|
version: '10'
|
|
53
|
+
- !ruby/object:Gem::Dependency
|
|
54
|
+
name: mcp
|
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - "~>"
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '1.1'
|
|
60
|
+
type: :runtime
|
|
61
|
+
prerelease: false
|
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - "~>"
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '1.1'
|
|
53
67
|
- !ruby/object:Gem::Dependency
|
|
54
68
|
name: turbo-rails
|
|
55
69
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -152,6 +166,7 @@ files:
|
|
|
152
166
|
- app/controllers/admin_suite/application_controller.rb
|
|
153
167
|
- app/controllers/admin_suite/dashboard_controller.rb
|
|
154
168
|
- app/controllers/admin_suite/docs_controller.rb
|
|
169
|
+
- app/controllers/admin_suite/mcp_controller.rb
|
|
155
170
|
- app/controllers/admin_suite/portals_controller.rb
|
|
156
171
|
- app/controllers/admin_suite/resources_controller.rb
|
|
157
172
|
- app/helpers/admin_suite/base_helper.rb
|
|
@@ -205,8 +220,10 @@ files:
|
|
|
205
220
|
- lib/admin_suite.rb
|
|
206
221
|
- lib/admin_suite/auth.rb
|
|
207
222
|
- lib/admin_suite/auth/host_hook.rb
|
|
223
|
+
- lib/admin_suite/auth/host_user.rb
|
|
208
224
|
- lib/admin_suite/auth/http_basic.rb
|
|
209
225
|
- lib/admin_suite/auth/strategy.rb
|
|
226
|
+
- lib/admin_suite/authorization_context.rb
|
|
210
227
|
- lib/admin_suite/configuration.rb
|
|
211
228
|
- lib/admin_suite/definition_loader.rb
|
|
212
229
|
- lib/admin_suite/deprecation.rb
|
|
@@ -214,14 +231,21 @@ files:
|
|
|
214
231
|
- lib/admin_suite/host_autoload_policy.rb
|
|
215
232
|
- lib/admin_suite/legacy_custom_renderer_procs.rb
|
|
216
233
|
- lib/admin_suite/markdown_renderer.rb
|
|
234
|
+
- lib/admin_suite/mcp.rb
|
|
235
|
+
- lib/admin_suite/mcp/authorization.rb
|
|
236
|
+
- lib/admin_suite/mcp/serializer.rb
|
|
237
|
+
- lib/admin_suite/mcp/tools/aggregate.rb
|
|
238
|
+
- lib/admin_suite/mcp/tools/describe_resources.rb
|
|
239
|
+
- lib/admin_suite/mcp/tools/get_record.rb
|
|
240
|
+
- lib/admin_suite/mcp/tools/list_records.rb
|
|
217
241
|
- lib/admin_suite/portal_definition.rb
|
|
218
242
|
- lib/admin_suite/portal_registry.rb
|
|
243
|
+
- lib/admin_suite/query.rb
|
|
219
244
|
- lib/admin_suite/renderer.rb
|
|
220
245
|
- lib/admin_suite/renderer_registry.rb
|
|
221
246
|
- lib/admin_suite/renderers/code_renderer.rb
|
|
222
247
|
- lib/admin_suite/renderers/json_renderer.rb
|
|
223
248
|
- lib/admin_suite/renderers/key_value_renderer.rb
|
|
224
|
-
- lib/admin_suite/renderers/legacy_gleania.rb
|
|
225
249
|
- lib/admin_suite/renderers/table_from_renderer.rb
|
|
226
250
|
- lib/admin_suite/section_definition.rb
|
|
227
251
|
- lib/admin_suite/theme_palette.rb
|
|
@@ -288,8 +312,17 @@ files:
|
|
|
288
312
|
- test/integration/chart_panel_test.rb
|
|
289
313
|
- test/integration/dashboard_test.rb
|
|
290
314
|
- test/integration/docs_test.rb
|
|
315
|
+
- test/integration/index_query_characterization_test.rb
|
|
291
316
|
- test/integration/index_table_test.rb
|
|
292
317
|
- test/integration/layout_assets_test.rb
|
|
318
|
+
- test/integration/mcp_aggregate_test.rb
|
|
319
|
+
- test/integration/mcp_authorization_test.rb
|
|
320
|
+
- test/integration/mcp_endpoint_test.rb
|
|
321
|
+
- test/integration/mcp_get_record_test.rb
|
|
322
|
+
- test/integration/mcp_instrumentation_test.rb
|
|
323
|
+
- test/integration/mcp_list_records_test.rb
|
|
324
|
+
- test/integration/mcp_parity_test.rb
|
|
325
|
+
- test/integration/mcp_release_test.rb
|
|
293
326
|
- test/integration/navigation_sections_test.rb
|
|
294
327
|
- test/integration/pagination_and_stats_test.rb
|
|
295
328
|
- test/integration/read_only_resource_test.rb
|
|
@@ -299,23 +332,27 @@ files:
|
|
|
299
332
|
- test/integration/toggle_test.rb
|
|
300
333
|
- test/lib/action_executor_redirect_test.rb
|
|
301
334
|
- test/lib/action_executor_test.rb
|
|
335
|
+
- test/lib/auth_host_user_test.rb
|
|
302
336
|
- test/lib/auth_http_basic_test.rb
|
|
303
337
|
- test/lib/auth_resolution_test.rb
|
|
304
338
|
- test/lib/auth_test.rb
|
|
339
|
+
- test/lib/authorization_context_test.rb
|
|
305
340
|
- test/lib/builtin_renderers_test.rb
|
|
306
341
|
- test/lib/definition_loader_test.rb
|
|
307
342
|
- test/lib/engine_defaults_test.rb
|
|
308
343
|
- test/lib/form_field_renderer_test.rb
|
|
309
344
|
- test/lib/format_table_cell_test.rb
|
|
310
345
|
- test/lib/index_includes_test.rb
|
|
311
|
-
- test/lib/legacy_renderer_deprecation_test.rb
|
|
312
346
|
- test/lib/markdown_renderer_test.rb
|
|
347
|
+
- test/lib/mcp_serializer_test.rb
|
|
348
|
+
- test/lib/query_test.rb
|
|
349
|
+
- test/lib/removed_deprecations_test.rb
|
|
313
350
|
- test/lib/renderer_test.rb
|
|
314
|
-
- test/lib/resource_exportable_deprecation_test.rb
|
|
315
351
|
- test/lib/resource_observability_extensions_test.rb
|
|
316
352
|
- test/lib/show_value_formatter_test.rb
|
|
317
353
|
- test/lib/theme_palette_test.rb
|
|
318
354
|
- test/lib/zeitwerk_integration_test.rb
|
|
355
|
+
- test/publish_workflow_test.rb
|
|
319
356
|
- test/test_helper.rb
|
|
320
357
|
homepage: https://github.com/techwright-lab/admin_suite
|
|
321
358
|
licenses:
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module AdminSuite
|
|
4
|
-
module Renderers
|
|
5
|
-
# The four Gleania-specific LLM chat-transcript renderers, moved verbatim
|
|
6
|
-
# out of `AdminSuite::BaseHelper` (role-coloured message bubbles, tool-call
|
|
7
|
-
# panels, prompt-template mustache highlighting).
|
|
8
|
-
#
|
|
9
|
-
# These are deprecated: they still work in 0.4.0 (logging a warning once
|
|
10
|
-
# per key per process the first time each is used), and are targeted for
|
|
11
|
-
# DELETION in 0.6.0 (moved from the originally-planned 0.5.0/Phase 2b,
|
|
12
|
-
# pending both the gleania and trust_growth host migrations). Gleania is
|
|
13
|
-
# expected to migrate to host-side renderer classes under
|
|
14
|
-
# `app/admin/renderers/*.rb` before then.
|
|
15
|
-
#
|
|
16
|
-
# The renderer bodies below are intentionally byte-equivalent to the
|
|
17
|
-
# BaseHelper methods they replace, other than `resource` -> `record` and
|
|
18
|
-
# routing BaseHelper method calls (`render_json_block`, `simple_format`,
|
|
19
|
-
# `concat`) through `view.` — this class is not `included` into the view,
|
|
20
|
-
# so those calls can't resolve as bare method sends the way they did
|
|
21
|
-
# inside the helper module. Do not "improve" this markup: a byte-for-byte
|
|
22
|
-
# move keeps gleania's Assistant/AI portal pages pixel-identical, and
|
|
23
|
-
# makes the eventual 0.6.0 deletion a clean removal.
|
|
24
|
-
module LegacyGleania
|
|
25
|
-
extend AdminSuite::Deprecation
|
|
26
|
-
|
|
27
|
-
DEPRECATION_MESSAGE_FORMAT =
|
|
28
|
-
"AdminSuite: the :%<key>s renderer is deprecated and will be removed in 0.6.0. " \
|
|
29
|
-
"Move it to app/admin/renderers in your app."
|
|
30
|
-
|
|
31
|
-
class << self
|
|
32
|
-
# Fires the deprecation sink at most once per `key` per process.
|
|
33
|
-
# `warn_once_sink` and `reset_deprecation_notices!` come from
|
|
34
|
-
# `AdminSuite::Deprecation`, extended above.
|
|
35
|
-
#
|
|
36
|
-
# @param key [Symbol]
|
|
37
|
-
# @return [void]
|
|
38
|
-
def warn_once(key)
|
|
39
|
-
super(key, format(DEPRECATION_MESSAGE_FORMAT, key: key))
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Verbatim from `BaseHelper#render_prompt_template`.
|
|
44
|
-
class PromptTemplateRenderer < Renderer
|
|
45
|
-
def render
|
|
46
|
-
LegacyGleania.warn_once(:prompt_template_preview)
|
|
47
|
-
|
|
48
|
-
template = record.respond_to?(:prompt_template) ? record.prompt_template : nil
|
|
49
|
-
return content_tag(:p, "No template defined", class: "text-slate-500 italic") if template.blank?
|
|
50
|
-
|
|
51
|
-
highlighted_template = h(template).gsub(/\{\{(\w+)\}\}/) do
|
|
52
|
-
"<span class=\"text-amber-400 bg-amber-900/30 px-1 rounded\">{{#{$1}}}</span>"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
content_tag(:div, class: "relative group") do
|
|
56
|
-
view.concat(content_tag(:div, class: "absolute top-2 right-2 flex items-center gap-2") do
|
|
57
|
-
view.concat(content_tag(:span, "TEMPLATE", class: "text-xs font-medium text-slate-400 uppercase tracking-wider"))
|
|
58
|
-
view.concat(content_tag(:button,
|
|
59
|
-
'<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/></svg>'.html_safe,
|
|
60
|
-
type: "button",
|
|
61
|
-
class: "p-1 text-slate-400 hover:text-slate-600 opacity-0 group-hover:opacity-100 transition-opacity",
|
|
62
|
-
data: { controller: "admin-suite--clipboard", action: "click->admin-suite--clipboard#copy", "admin-suite--clipboard-text-value": template },
|
|
63
|
-
title: "Copy to clipboard"))
|
|
64
|
-
end)
|
|
65
|
-
|
|
66
|
-
view.concat(content_tag(:pre, class: "bg-slate-900 text-slate-100 p-4 rounded-lg overflow-x-auto text-sm font-mono max-h-[600px] overflow-y-auto whitespace-pre-wrap leading-relaxed") do
|
|
67
|
-
highlighted_template.html_safe
|
|
68
|
-
end)
|
|
69
|
-
|
|
70
|
-
variables = template.scan(/\{\{(\w+)\}\}/).flatten.uniq
|
|
71
|
-
if variables.any?
|
|
72
|
-
view.concat(content_tag(:div, class: "mt-3 pt-3 border-t border-slate-700") do
|
|
73
|
-
view.concat(content_tag(:span, "Variables: ", class: "text-sm text-slate-400"))
|
|
74
|
-
view.concat(content_tag(:div, class: "inline-flex flex-wrap gap-1 mt-1") do
|
|
75
|
-
variables.each do |var|
|
|
76
|
-
view.concat(content_tag(:code, "{{#{var}}}", class: "text-xs px-2 py-0.5 bg-amber-900/30 text-amber-400 rounded"))
|
|
77
|
-
end
|
|
78
|
-
end)
|
|
79
|
-
end)
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Verbatim from `BaseHelper#render_messages_preview`.
|
|
86
|
-
class MessagesPreviewRenderer < Renderer
|
|
87
|
-
def render
|
|
88
|
-
LegacyGleania.warn_once(:messages_preview)
|
|
89
|
-
|
|
90
|
-
messages = record.respond_to?(:messages) ? record.messages : []
|
|
91
|
-
if messages.respond_to?(:chronological)
|
|
92
|
-
messages = messages.chronological
|
|
93
|
-
end
|
|
94
|
-
messages = messages.limit(50) if messages.respond_to?(:limit)
|
|
95
|
-
messages = Array.wrap(messages)
|
|
96
|
-
|
|
97
|
-
return content_tag(:p, "No messages", class: "text-slate-500 italic") if messages.blank?
|
|
98
|
-
|
|
99
|
-
content_tag(:div, class: "space-y-4 max-h-[600px] overflow-y-auto -mx-6 -mb-6 p-6 pt-0") do
|
|
100
|
-
messages.each_with_index do |msg, idx|
|
|
101
|
-
if msg.respond_to?(:role)
|
|
102
|
-
role = msg.role
|
|
103
|
-
content = msg.content
|
|
104
|
-
created_at = msg.respond_to?(:created_at) ? msg.created_at : nil
|
|
105
|
-
else
|
|
106
|
-
role = msg["role"] || msg[:role] || "unknown"
|
|
107
|
-
content = msg["content"] || msg[:content] || ""
|
|
108
|
-
created_at = msg["created_at"] || msg[:created_at]
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
role_class = case role.to_s
|
|
112
|
-
when "user" then "bg-blue-50 border-blue-200"
|
|
113
|
-
when "assistant" then "bg-emerald-50 border-emerald-200"
|
|
114
|
-
when "tool" then "bg-amber-50 border-amber-200"
|
|
115
|
-
when "system" then "bg-slate-50 border-slate-200"
|
|
116
|
-
else "bg-slate-50 border-slate-200"
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
role_icon = case role.to_s
|
|
120
|
-
when "user"
|
|
121
|
-
'<svg class="w-4 h-4 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/></svg>'.html_safe
|
|
122
|
-
when "assistant"
|
|
123
|
-
'<svg class="w-4 h-4 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"/></svg>'.html_safe
|
|
124
|
-
when "tool"
|
|
125
|
-
'<svg class="w-4 h-4 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/></svg>'.html_safe
|
|
126
|
-
else
|
|
127
|
-
'<svg class="w-4 h-4 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/></svg>'.html_safe
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
view.concat(content_tag(:div, class: "rounded-lg border p-4 #{role_class}") do
|
|
131
|
-
view.concat(content_tag(:div, class: "flex items-center justify-between mb-3") do
|
|
132
|
-
view.concat(content_tag(:div, class: "flex items-center gap-2") do
|
|
133
|
-
view.concat(role_icon)
|
|
134
|
-
view.concat(content_tag(:span, role.to_s.capitalize, class: "text-sm font-medium text-slate-700"))
|
|
135
|
-
end)
|
|
136
|
-
view.concat(content_tag(:div, class: "flex items-center gap-2 text-xs text-slate-400") do
|
|
137
|
-
view.concat(content_tag(:span, created_at.strftime("%H:%M:%S"))) if created_at.respond_to?(:strftime)
|
|
138
|
-
view.concat(content_tag(:span, "##{idx + 1}"))
|
|
139
|
-
end)
|
|
140
|
-
end)
|
|
141
|
-
|
|
142
|
-
content_str = content.to_s
|
|
143
|
-
if role.to_s == "tool" && content_str.start_with?("{", "[")
|
|
144
|
-
begin
|
|
145
|
-
parsed = JSON.parse(content_str)
|
|
146
|
-
view.concat(view.render_json_block(parsed))
|
|
147
|
-
rescue JSON::ParserError
|
|
148
|
-
view.concat(content_tag(:div, view.simple_format(h(content_str)), class: "prose prose-sm max-w-none"))
|
|
149
|
-
end
|
|
150
|
-
else
|
|
151
|
-
view.concat(content_tag(:div, view.simple_format(h(content_str)), class: "prose prose-sm max-w-none"))
|
|
152
|
-
end
|
|
153
|
-
end)
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# Verbatim from `BaseHelper#render_tool_args_preview`.
|
|
160
|
-
class ToolArgsRenderer < Renderer
|
|
161
|
-
def render
|
|
162
|
-
LegacyGleania.warn_once(:tool_args_preview)
|
|
163
|
-
|
|
164
|
-
args = record.respond_to?(:args) ? record.args : (record.respond_to?(:arguments) ? record.arguments : {})
|
|
165
|
-
result = record.respond_to?(:result) ? record.result : nil
|
|
166
|
-
error = record.respond_to?(:error) ? record.error : nil
|
|
167
|
-
|
|
168
|
-
content_tag(:div, class: "space-y-6") do
|
|
169
|
-
view.concat(content_tag(:div) do
|
|
170
|
-
view.concat(content_tag(:h4, "Arguments", class: "text-sm font-medium text-slate-500 mb-2"))
|
|
171
|
-
if args.present? && args != {}
|
|
172
|
-
view.concat(view.render_json_block(args))
|
|
173
|
-
else
|
|
174
|
-
view.concat(content_tag(:p, "No arguments", class: "text-slate-400 italic text-sm"))
|
|
175
|
-
end
|
|
176
|
-
end)
|
|
177
|
-
|
|
178
|
-
if result.present? && result != {}
|
|
179
|
-
view.concat(content_tag(:div, class: "pt-4 border-t border-slate-200") do
|
|
180
|
-
view.concat(content_tag(:h4, "Result", class: "text-sm font-medium text-slate-500 mb-2"))
|
|
181
|
-
view.concat(view.render_json_block(result))
|
|
182
|
-
end)
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
if error.present?
|
|
186
|
-
view.concat(content_tag(:div, class: "pt-4 border-t border-slate-200") do
|
|
187
|
-
view.concat(content_tag(:h4, "Error", class: "text-sm font-medium text-red-500 mb-2"))
|
|
188
|
-
view.concat(content_tag(:div, class: "bg-red-50 border border-red-200 rounded-lg p-4") do
|
|
189
|
-
content_tag(:pre, h(error.to_s), class: "text-sm text-red-700 whitespace-pre-wrap font-mono")
|
|
190
|
-
end)
|
|
191
|
-
end)
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
# Verbatim from `BaseHelper#render_turn_messages_preview`.
|
|
198
|
-
class TurnMessagesRenderer < Renderer
|
|
199
|
-
def render
|
|
200
|
-
LegacyGleania.warn_once(:turn_messages_preview)
|
|
201
|
-
|
|
202
|
-
user_msg = record.respond_to?(:user_message) ? record.user_message : nil
|
|
203
|
-
asst_msg = record.respond_to?(:assistant_message) ? record.assistant_message : nil
|
|
204
|
-
|
|
205
|
-
content_tag(:div, class: "space-y-4") do
|
|
206
|
-
if user_msg
|
|
207
|
-
view.concat(content_tag(:div, class: "rounded-lg border p-4 bg-blue-50 border-blue-200") do
|
|
208
|
-
view.concat(content_tag(:div, class: "flex items-center gap-2 mb-2") do
|
|
209
|
-
view.concat('<svg class="w-4 h-4 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/></svg>'.html_safe)
|
|
210
|
-
view.concat(content_tag(:span, "User", class: "text-sm font-medium text-slate-700"))
|
|
211
|
-
end)
|
|
212
|
-
view.concat(content_tag(:div, view.simple_format(h(user_msg.respond_to?(:content) ? user_msg.content.to_s : user_msg.to_s)), class: "prose prose-sm max-w-none"))
|
|
213
|
-
end)
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
if asst_msg
|
|
217
|
-
view.concat(content_tag(:div, class: "rounded-lg border p-4 bg-emerald-50 border-emerald-200") do
|
|
218
|
-
view.concat(content_tag(:div, class: "flex items-center gap-2 mb-2") do
|
|
219
|
-
view.concat('<svg class="w-4 h-4 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"/></svg>'.html_safe)
|
|
220
|
-
view.concat(content_tag(:span, "Assistant", class: "text-sm font-medium text-slate-700"))
|
|
221
|
-
end)
|
|
222
|
-
view.concat(content_tag(:div, view.simple_format(h(asst_msg.respond_to?(:content) ? asst_msg.content.to_s : asst_msg.to_s)), class: "prose prose-sm max-w-none"))
|
|
223
|
-
end)
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
view.concat(content_tag(:p, "No messages found", class: "text-slate-400 italic text-sm")) unless user_msg || asst_msg
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "test_helper"
|
|
4
|
-
|
|
5
|
-
module AdminSuite
|
|
6
|
-
class LegacyRendererDeprecationTest < ActionView::TestCase
|
|
7
|
-
include ::ERB::Util
|
|
8
|
-
include AdminSuite::BaseHelper
|
|
9
|
-
|
|
10
|
-
Prompt = Struct.new(:prompt_template)
|
|
11
|
-
|
|
12
|
-
setup { AdminSuite::Renderers::LegacyGleania.reset_deprecation_notices! }
|
|
13
|
-
|
|
14
|
-
test "the legacy prompt renderer still renders its template" do
|
|
15
|
-
html = render_custom_section(Prompt.new("Hello {{name}}"), :prompt_template_preview)
|
|
16
|
-
assert_includes html, "Hello"
|
|
17
|
-
assert_includes html, "name"
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
test "using a legacy renderer logs a deprecation once per key" do
|
|
21
|
-
logged = []
|
|
22
|
-
AdminSuite::Renderers::LegacyGleania.stub(:warn_once_sink, ->(msg) { logged << msg }) do
|
|
23
|
-
2.times { render_custom_section(Prompt.new("x"), :prompt_template_preview) }
|
|
24
|
-
end
|
|
25
|
-
assert_equal 1, logged.size
|
|
26
|
-
assert_includes logged.first, "deprecated"
|
|
27
|
-
# Deliberately a hardcoded literal, not read off
|
|
28
|
-
# DEPRECATION_MESSAGE_FORMAT: reading the version out of the constant
|
|
29
|
-
# under test and asserting the message contains it is true by
|
|
30
|
-
# construction (format() only substitutes %<key>s, never the version
|
|
31
|
-
# digits), so it can never fail on a wrong retarget -- exactly the
|
|
32
|
-
# property this test exists to catch. If the removal target changes
|
|
33
|
-
# again, this literal must be updated by hand; that's the point.
|
|
34
|
-
assert_includes logged.first, "0.6.0"
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
test "the gem no longer includes the host CustomRenderersHelper constant" do
|
|
38
|
-
source = AdminSuite::Engine.root.join("app/helpers/admin_suite/base_helper.rb").read
|
|
39
|
-
refute_includes source, "Internal::Developer::CustomRenderersHelper"
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "test_helper"
|
|
4
|
-
|
|
5
|
-
module AdminSuite
|
|
6
|
-
class ResourceExportableDeprecationTest < ActiveSupport::TestCase
|
|
7
|
-
# Regression fixture for Finding 1 of the whole-branch review: Task 8
|
|
8
|
-
# removed `exportable` after grepping the *gem* for readers, but host
|
|
9
|
-
# apps are *callers* of this DSL (gleania: 30 resource files;
|
|
10
|
-
# trust_growth: 1). A real removal raises `NoMethodError` at
|
|
11
|
-
# definition-load time -- and in production `DefinitionLoader` logs and
|
|
12
|
-
# swallows that, so the resource silently vanishes from the admin.
|
|
13
|
-
class LegacyExportableResource < Admin::Base::Resource
|
|
14
|
-
exportable :json, :csv
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
setup { LegacyExportableResource.reset_deprecation_notices! }
|
|
18
|
-
|
|
19
|
-
test "calling exportable in a resource body is harmless" do
|
|
20
|
-
assert_nothing_raised { LegacyExportableResource.exportable(:json, :csv) }
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
test "exportable does not restore any export-format reader" do
|
|
24
|
-
refute LegacyExportableResource.respond_to?(:export_formats)
|
|
25
|
-
refute LegacyExportableResource.instance_variable_defined?(:@export_formats)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
test "exportable warns once per resource class, naming the class and the 0.6.0 removal" do
|
|
29
|
-
logged = []
|
|
30
|
-
LegacyExportableResource.stub(:warn_once_sink, ->(msg) { logged << msg }) do
|
|
31
|
-
2.times { LegacyExportableResource.exportable(:json, :csv) }
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
assert_equal 1, logged.size
|
|
35
|
-
assert_includes logged.first, "LegacyExportableResource"
|
|
36
|
-
# Deliberately a hardcoded literal, not read off
|
|
37
|
-
# EXPORTABLE_DEPRECATION_MESSAGE_FORMAT: reading the version out of
|
|
38
|
-
# the constant under test and asserting the message contains it is
|
|
39
|
-
# true by construction (format() only substitutes %<resource>s, never
|
|
40
|
-
# the version digits), so it can never fail on a wrong retarget --
|
|
41
|
-
# exactly the property this test exists to catch. If the removal
|
|
42
|
-
# target changes again, this literal must be updated by hand; that's
|
|
43
|
-
# the point.
|
|
44
|
-
assert_includes logged.first, "0.6.0"
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|