legate 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +345 -0
- data/bin/legate +13 -0
- data/examples/00_quickstart.rb +51 -0
- data/examples/01_simple_agent.rb +105 -0
- data/examples/02_multi_tool_agent.rb +140 -0
- data/examples/03_custom_tool.rb +93 -0
- data/examples/04_agent_instructions.rb +84 -0
- data/examples/05_state_and_sessions.rb +91 -0
- data/examples/06_callbacks.rb +186 -0
- data/examples/07_async_jobs.rb +112 -0
- data/examples/08_loop_agent.rb +197 -0
- data/examples/09_sequential_workflow.rb +40 -0
- data/examples/10_parallel_workflow.rb +34 -0
- data/examples/11_agent_delegation.rb +24 -0
- data/examples/12_http_client_tool.rb +156 -0
- data/examples/13_authentication.rb +220 -0
- data/examples/14_mcp_client.rb +154 -0
- data/examples/15_mcp_server.rb +79 -0
- data/examples/16_webhooks.rb +91 -0
- data/examples/README_sequential_agents.md +164 -0
- data/examples/advanced/auth/cookie_auth_tool.rb +146 -0
- data/examples/advanced/auth/custom_auth_flows_example.rb +626 -0
- data/examples/advanced/auth/excon_middleware.rb +317 -0
- data/examples/advanced/auth/excon_middleware_auth.rb +399 -0
- data/examples/advanced/auth/fiber_auth_example.rb +281 -0
- data/examples/advanced/auth/fiber_oidc_example.rb +403 -0
- data/examples/advanced/auth/httpbin_bearer_tool.rb +159 -0
- data/examples/advanced/auth/oauth2_auth.rb +419 -0
- data/examples/advanced/auth/oidc_auth.rb +514 -0
- data/examples/advanced/auth/openweather_api.rb +251 -0
- data/examples/advanced/auth/openweather_tool.rb +153 -0
- data/examples/advanced/auth/query_param_middleware_test.rb +138 -0
- data/examples/advanced/auth/service_account.rb +135 -0
- data/examples/advanced/auth/test_with_httpbin.rb +202 -0
- data/examples/advanced/auth/token_lifecycle_example.rb +428 -0
- data/examples/advanced/callback_monitoring.rb +679 -0
- data/examples/advanced/mas/fixed_delegation_example.rb +191 -0
- data/examples/advanced/mas/loop_workflow.rb +28 -0
- data/examples/advanced/mas/mock_planner.rb +77 -0
- data/examples/advanced/mas/proper_delegation_example.rb +276 -0
- data/examples/advanced/mcp/legate_mcp_server_resource_example.rb +182 -0
- data/examples/advanced/mcp/mcp_resource_server_example.rb +309 -0
- data/examples/advanced/mcp/mcp_server_async.rb +76 -0
- data/examples/advanced/mcp/mcp_server_async_tools.rb +122 -0
- data/examples/advanced/mcp/mcp_server_legate_agent.rb +95 -0
- data/examples/advanced/mcp/mcp_server_rack.rb +89 -0
- data/examples/advanced/random_calculator.rb +104 -0
- data/examples/advanced/sleep_agent.rb +153 -0
- data/examples/advanced/webhooks/webhook_e2e_runner.rb +110 -0
- data/examples/advanced/webhooks/webhook_receiver_agent.rb +58 -0
- data/examples/advanced/workflows/task_refinement_loop_agent.rb +278 -0
- data/examples/advanced/workflows/travel_planner_auto_sequential.rb +444 -0
- data/examples/advanced/workflows/travel_planner_parallel.rb +656 -0
- data/examples/advanced/workflows/travel_planner_sequential.rb +512 -0
- data/examples/tools/oauth2_example.rb +136 -0
- data/examples/tools/sleepy_tool.rb +42 -0
- data/lib/legate/activity_log.rb +71 -0
- data/lib/legate/agent.rb +959 -0
- data/lib/legate/agent_code_generator.rb +185 -0
- data/lib/legate/agent_definition.rb +812 -0
- data/lib/legate/agentic/decision.rb +49 -0
- data/lib/legate/agentic/loop.rb +134 -0
- data/lib/legate/agentic.rb +5 -0
- data/lib/legate/agents/loop_agent.rb +248 -0
- data/lib/legate/agents/parallel_agent.rb +163 -0
- data/lib/legate/agents/sequential_agent.rb +190 -0
- data/lib/legate/agents.rb +14 -0
- data/lib/legate/auth/config.rb +148 -0
- data/lib/legate/auth/coordinator.rb +218 -0
- data/lib/legate/auth/coordinators/oauth2_coordinator.rb +99 -0
- data/lib/legate/auth/coordinators/oidc_coordinator.rb +68 -0
- data/lib/legate/auth/coordinators/service_account_coordinator.rb +122 -0
- data/lib/legate/auth/credential.rb +157 -0
- data/lib/legate/auth/encryption.rb +108 -0
- data/lib/legate/auth/error.rb +94 -0
- data/lib/legate/auth/exchanged_credential.rb +180 -0
- data/lib/legate/auth/excon_middleware.rb +285 -0
- data/lib/legate/auth/http_client_utils.rb +364 -0
- data/lib/legate/auth/manager.rb +531 -0
- data/lib/legate/auth/manager_store.rb +394 -0
- data/lib/legate/auth/middleware_factory.rb +290 -0
- data/lib/legate/auth/runner.rb +279 -0
- data/lib/legate/auth/scheme.rb +125 -0
- data/lib/legate/auth/schemes/api_key.rb +212 -0
- data/lib/legate/auth/schemes/google_service_account.rb +108 -0
- data/lib/legate/auth/schemes/http_bearer.rb +98 -0
- data/lib/legate/auth/schemes/oauth2.rb +396 -0
- data/lib/legate/auth/schemes/openid_connect.rb +346 -0
- data/lib/legate/auth/schemes/service_account.rb +388 -0
- data/lib/legate/auth/schemes.rb +40 -0
- data/lib/legate/auth/token_manager.rb +362 -0
- data/lib/legate/auth/token_store.rb +86 -0
- data/lib/legate/auth/tool_context_extension.rb +97 -0
- data/lib/legate/auth/tool_integration.rb +188 -0
- data/lib/legate/auth/url_guard.rb +81 -0
- data/lib/legate/auth.rb +453 -0
- data/lib/legate/callbacks/callback_context.rb +71 -0
- data/lib/legate/cli/agent_commands.rb +950 -0
- data/lib/legate/cli/auth_commands.rb +520 -0
- data/lib/legate/cli/base_command.rb +24 -0
- data/lib/legate/cli/deployment_commands.rb +934 -0
- data/lib/legate/cli/output_helper.rb +108 -0
- data/lib/legate/cli/session_commands.rb +138 -0
- data/lib/legate/cli/skaffold_commands.rb +223 -0
- data/lib/legate/cli/tool_commands.rb +261 -0
- data/lib/legate/cli/web_commands.rb +182 -0
- data/lib/legate/cli.rb +40 -0
- data/lib/legate/configuration/webhooks.rb +113 -0
- data/lib/legate/configuration.rb +39 -0
- data/lib/legate/definition_store.rb +23 -0
- data/lib/legate/errors.rb +118 -0
- data/lib/legate/event.rb +161 -0
- data/lib/legate/gemini_ai_beta_patch.rb +39 -0
- data/lib/legate/generators/agent_generator.rb +412 -0
- data/lib/legate/generators/code_validator.rb +48 -0
- data/lib/legate/generators/legate/install_generator.rb +35 -0
- data/lib/legate/generators/legate/templates/create_legate_tables.rb.tt +36 -0
- data/lib/legate/generators/legate/templates/initializer.rb +18 -0
- data/lib/legate/generators/runtime_tool_loader.rb +76 -0
- data/lib/legate/generators/tool_generator.rb +408 -0
- data/lib/legate/generators.rb +11 -0
- data/lib/legate/global_definition_registry.rb +506 -0
- data/lib/legate/global_tool_manager.rb +135 -0
- data/lib/legate/llm/adapter.rb +69 -0
- data/lib/legate/llm/gemini.rb +172 -0
- data/lib/legate/llm/ollama.rb +80 -0
- data/lib/legate/llm.rb +34 -0
- data/lib/legate/mcp/client.rb +320 -0
- data/lib/legate/mcp/connection/sse.rb +292 -0
- data/lib/legate/mcp/connection/stdio.rb +273 -0
- data/lib/legate/mcp/connection_manager.rb +103 -0
- data/lib/legate/mcp/server/legate_agent_adapter.rb +170 -0
- data/lib/legate/mcp/server/legate_direct_agent_adapter.rb +140 -0
- data/lib/legate/mcp/server/legate_tool_adapter.rb +119 -0
- data/lib/legate/mcp/tool_wrapper.rb +138 -0
- data/lib/legate/mcp/util/schema_converter.rb +134 -0
- data/lib/legate/mcp.rb +23 -0
- data/lib/legate/plan_executor.rb +375 -0
- data/lib/legate/planner.rb +839 -0
- data/lib/legate/rails/railtie.rb +43 -0
- data/lib/legate/rails.rb +9 -0
- data/lib/legate/redaction.rb +32 -0
- data/lib/legate/session.rb +299 -0
- data/lib/legate/session_service/active_record.rb +300 -0
- data/lib/legate/session_service/base.rb +68 -0
- data/lib/legate/session_service/event_broadcast.rb +74 -0
- data/lib/legate/session_service/in_memory.rb +188 -0
- data/lib/legate/tool/metadata_dsl.rb +122 -0
- data/lib/legate/tool.rb +276 -0
- data/lib/legate/tool_code_generator.rb +103 -0
- data/lib/legate/tool_context.rb +350 -0
- data/lib/legate/tool_loader.rb +39 -0
- data/lib/legate/tool_registry.rb +73 -0
- data/lib/legate/tool_result.rb +61 -0
- data/lib/legate/tools/agent_tool.rb +187 -0
- data/lib/legate/tools/base/http_client.rb +319 -0
- data/lib/legate/tools/base/safe_url.rb +56 -0
- data/lib/legate/tools/base_async_job_tool.rb +91 -0
- data/lib/legate/tools/calculator.rb +89 -0
- data/lib/legate/tools/cat_facts.rb +81 -0
- data/lib/legate/tools/check_job_status_tool.rb +48 -0
- data/lib/legate/tools/current_time_tool.rb +64 -0
- data/lib/legate/tools/echo.rb +43 -0
- data/lib/legate/tools/http_request_tool.rb +105 -0
- data/lib/legate/tools/random_number_tool.rb +64 -0
- data/lib/legate/tools/read_webpage_tool.rb +92 -0
- data/lib/legate/tools/sleepy_tool.rb +74 -0
- data/lib/legate/tools/webhook_tool.rb +146 -0
- data/lib/legate/version.rb +5 -0
- data/lib/legate/web/app.rb +984 -0
- data/lib/legate/web/public/css/main.css +4980 -0
- data/lib/legate/web/public/images/favicon-256.png +0 -0
- data/lib/legate/web/public/images/favicon-32.png +0 -0
- data/lib/legate/web/public/images/legate-logo-dark.png +0 -0
- data/lib/legate/web/public/images/legate-logo-light.png +0 -0
- data/lib/legate/web/public/js/legate.js +616 -0
- data/lib/legate/web/public/styles/main.scss +4402 -0
- data/lib/legate/web/routes/agent_authentication_routes.rb +530 -0
- data/lib/legate/web/routes/agent_definition_routes.rb +803 -0
- data/lib/legate/web/routes/agent_generator_routes.rb +80 -0
- data/lib/legate/web/routes/agent_interaction_routes.rb +734 -0
- data/lib/legate/web/routes/agent_runtime_routes.rb +323 -0
- data/lib/legate/web/routes/api_routes.rb +56 -0
- data/lib/legate/web/routes/authentication_routes.rb +1541 -0
- data/lib/legate/web/routes/core_routes.rb +111 -0
- data/lib/legate/web/routes/documentation_routes.rb +220 -0
- data/lib/legate/web/routes/tool_generator_routes.rb +81 -0
- data/lib/legate/web/routes/tools_ui_routes.rb +207 -0
- data/lib/legate/web/sass_compiler.rb +73 -0
- data/lib/legate/web/views/_active_session_info.slim +25 -0
- data/lib/legate/web/views/_activity_list.slim +55 -0
- data/lib/legate/web/views/_agent_card.slim +56 -0
- data/lib/legate/web/views/_agent_generator_modal.slim +382 -0
- data/lib/legate/web/views/_agent_status_controls.slim +71 -0
- data/lib/legate/web/views/_agent_tool_table.slim +74 -0
- data/lib/legate/web/views/_chat_message.slim +95 -0
- data/lib/legate/web/views/_display_agent_configuration.slim +26 -0
- data/lib/legate/web/views/_display_agent_description.slim +11 -0
- data/lib/legate/web/views/_display_agent_fallback.slim +15 -0
- data/lib/legate/web/views/_display_agent_hierarchy.slim +93 -0
- data/lib/legate/web/views/_display_agent_instruction.slim +17 -0
- data/lib/legate/web/views/_display_agent_mcp.slim +13 -0
- data/lib/legate/web/views/_display_agent_model.slim +17 -0
- data/lib/legate/web/views/_display_agent_name.slim +42 -0
- data/lib/legate/web/views/_display_agent_output_key.slim +26 -0
- data/lib/legate/web/views/_display_agent_type.slim +65 -0
- data/lib/legate/web/views/_edit_agent_configuration.slim +74 -0
- data/lib/legate/web/views/_edit_agent_description.slim +16 -0
- data/lib/legate/web/views/_edit_agent_fallback.slim +25 -0
- data/lib/legate/web/views/_edit_agent_hierarchy.slim +98 -0
- data/lib/legate/web/views/_edit_agent_instruction.slim +49 -0
- data/lib/legate/web/views/_edit_agent_mcp.slim +33 -0
- data/lib/legate/web/views/_edit_agent_model.slim +23 -0
- data/lib/legate/web/views/_edit_agent_output_key.slim +36 -0
- data/lib/legate/web/views/_edit_agent_tools.slim +40 -0
- data/lib/legate/web/views/_edit_agent_type.slim +67 -0
- data/lib/legate/web/views/_session_error.slim +4 -0
- data/lib/legate/web/views/_skeleton.slim +69 -0
- data/lib/legate/web/views/_tool_card.slim +9 -0
- data/lib/legate/web/views/_tool_generator_modal.slim +311 -0
- data/lib/legate/web/views/agent.slim +436 -0
- data/lib/legate/web/views/agent_auth.slim +562 -0
- data/lib/legate/web/views/agents.slim +369 -0
- data/lib/legate/web/views/auth.slim +112 -0
- data/lib/legate/web/views/auth_credential_detail.slim +327 -0
- data/lib/legate/web/views/auth_credentials.slim +261 -0
- data/lib/legate/web/views/auth_debug.slim +94 -0
- data/lib/legate/web/views/auth_mapping_detail.slim +151 -0
- data/lib/legate/web/views/auth_mapping_new.slim +123 -0
- data/lib/legate/web/views/auth_mappings.slim +120 -0
- data/lib/legate/web/views/auth_scheme_detail.slim +274 -0
- data/lib/legate/web/views/auth_schemes.slim +259 -0
- data/lib/legate/web/views/auth_test.slim +418 -0
- data/lib/legate/web/views/chat.slim +192 -0
- data/lib/legate/web/views/docs_index.slim +105 -0
- data/lib/legate/web/views/docs_show.slim +105 -0
- data/lib/legate/web/views/error_404.slim +5 -0
- data/lib/legate/web/views/index.slim +148 -0
- data/lib/legate/web/views/layout.slim +144 -0
- data/lib/legate/web/views/tool_detail.slim +87 -0
- data/lib/legate/web/views/tools.slim +50 -0
- data/lib/legate/web/webhook_listener.rb +367 -0
- data/lib/legate/web.rb +9 -0
- data/lib/legate.rb +220 -0
- data/public/docs/advanced/callbacks.md +828 -0
- data/public/docs/advanced/mcp_schema_conversion.md +59 -0
- data/public/docs/authentication/api_reference/config.md +210 -0
- data/public/docs/authentication/api_reference/credential.md +246 -0
- data/public/docs/authentication/api_reference/encryption.md +218 -0
- data/public/docs/authentication/api_reference/exchanged_credential.md +271 -0
- data/public/docs/authentication/api_reference/excon_middleware.md +175 -0
- data/public/docs/authentication/api_reference/index.md +30 -0
- data/public/docs/authentication/api_reference/scheme.md +250 -0
- data/public/docs/authentication/api_reference/schemes/api_key.md +175 -0
- data/public/docs/authentication/api_reference/schemes/google_service_account.md +221 -0
- data/public/docs/authentication/api_reference/schemes/http_bearer.md +169 -0
- data/public/docs/authentication/api_reference/schemes/oauth2.md +343 -0
- data/public/docs/authentication/api_reference/schemes/oidc.md +73 -0
- data/public/docs/authentication/api_reference/schemes/openid_connect.md +311 -0
- data/public/docs/authentication/api_reference/schemes/service_account.md +287 -0
- data/public/docs/authentication/api_reference/token_manager.md +221 -0
- data/public/docs/authentication/api_reference/token_store.md +146 -0
- data/public/docs/authentication/api_reference/tool_context_extension.md +166 -0
- data/public/docs/authentication/guides/api_key.md +190 -0
- data/public/docs/authentication/guides/bearer.md +172 -0
- data/public/docs/authentication/guides/configuration.md +255 -0
- data/public/docs/authentication/guides/custom_flow.md +523 -0
- data/public/docs/authentication/guides/index.md +24 -0
- data/public/docs/authentication/guides/migration.md +435 -0
- data/public/docs/authentication/guides/oauth2.md +252 -0
- data/public/docs/authentication/guides/oidc.md +241 -0
- data/public/docs/authentication/guides/overview.md +155 -0
- data/public/docs/authentication/guides/secure_storage.md +301 -0
- data/public/docs/authentication/guides/service_account.md +228 -0
- data/public/docs/authentication/guides/token_lifecycle.md +295 -0
- data/public/docs/authentication/guides/web_ui_integration.md +504 -0
- data/public/docs/authentication/index.md +58 -0
- data/public/docs/authentication/troubleshooting/credential_storage.md +550 -0
- data/public/docs/authentication/troubleshooting/environment_variables.md +540 -0
- data/public/docs/authentication/troubleshooting/index.md +11 -0
- data/public/docs/authentication/troubleshooting/oauth2_issues.md +220 -0
- data/public/docs/authentication/troubleshooting/oidc_issues.md +412 -0
- data/public/docs/authentication/troubleshooting/token_refresh.md +338 -0
- data/public/docs/cli/legate_cli_usage.md +363 -0
- data/public/docs/core_concepts/legate_agent_lifecycle.md +124 -0
- data/public/docs/core_concepts/legate_architecture_overview.md +110 -0
- data/public/docs/core_concepts/legate_configuration.md +116 -0
- data/public/docs/core_concepts/legate_definition_store.md +102 -0
- data/public/docs/core_concepts/legate_planner.md +94 -0
- data/public/docs/core_concepts/legate_session_service.md +104 -0
- data/public/docs/error_handling/legate_error_handling.md +122 -0
- data/public/docs/examples.md +199 -0
- data/public/docs/getting_started.md +111 -0
- data/public/docs/guides/agentic_agents.md +137 -0
- data/public/docs/guides/ai_code_generators.md +437 -0
- data/public/docs/guides/auto_loading.md +326 -0
- data/public/docs/guides/configuring_agent_webhooks.md +219 -0
- data/public/docs/guides/http_client_usage.md +264 -0
- data/public/docs/guides/llm_providers.md +137 -0
- data/public/docs/guides/mcp_client_integration.md +232 -0
- data/public/docs/guides/mcp_server_exposure.md +206 -0
- data/public/docs/guides/rails_integration.md +128 -0
- data/public/docs/guides/sending_outbound_webhooks.md +227 -0
- data/public/docs/guides/streaming.md +112 -0
- data/public/docs/guides/webhooks.md +288 -0
- data/public/docs/introduction.md +51 -0
- data/public/docs/multi_agent_systems/advanced_features.md +57 -0
- data/public/docs/multi_agent_systems/agent_delegation.md +190 -0
- data/public/docs/multi_agent_systems/agent_hierarchy.md +49 -0
- data/public/docs/multi_agent_systems/state_management.md +47 -0
- data/public/docs/multi_agent_systems/workflow_agents.md +72 -0
- data/public/docs/tools/legate_built_in_tools.md +332 -0
- data/public/docs/tools/legate_tools_and_registry.md +263 -0
- data/public/docs/web_ui/legate_web_ui.md +137 -0
- metadata +823 -0
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
/ Agent Authentication Management Page
|
|
2
|
+
.container
|
|
3
|
+
.section
|
|
4
|
+
.level
|
|
5
|
+
.level-left
|
|
6
|
+
.level-item
|
|
7
|
+
div
|
|
8
|
+
h1.title.is-3 Authentication for Agent: #{@agent_auth_data[:name]}
|
|
9
|
+
p.subtitle.is-5.mt-1 #{@agent_auth_data[:description]}
|
|
10
|
+
.level-right
|
|
11
|
+
.level-item
|
|
12
|
+
a.button.is-light href="/agents/#{@agent_auth_data[:name]}"
|
|
13
|
+
span.icon
|
|
14
|
+
i.fas.fa-arrow-left
|
|
15
|
+
span Back to Agent
|
|
16
|
+
|
|
17
|
+
/ Authentication Status Card
|
|
18
|
+
.card.mb-5
|
|
19
|
+
.card-header
|
|
20
|
+
.card-header-title
|
|
21
|
+
span.icon.mr-2
|
|
22
|
+
i.fas.fa-shield-alt
|
|
23
|
+
| Authentication Status
|
|
24
|
+
.card-content
|
|
25
|
+
- status = @agent_auth_data[:auth_status]
|
|
26
|
+
.notification class="is-#{status[:status] == :success ? 'success' : status[:status] == :warning ? 'warning' : 'danger'}"
|
|
27
|
+
.level
|
|
28
|
+
.level-left
|
|
29
|
+
.level-item
|
|
30
|
+
span.icon
|
|
31
|
+
i.fas class="fa-#{status[:status] == :success ? 'check-circle' : status[:status] == :warning ? 'exclamation-triangle' : 'times-circle'}"
|
|
32
|
+
strong #{status[:message]}
|
|
33
|
+
.level-right
|
|
34
|
+
.level-item
|
|
35
|
+
button.button.is-small.is-outlined id="refresh-status" hx-get="/agents/#{@agent_auth_data[:name]}/auth/status" hx-target="#status-details" hx-swap="innerHTML"
|
|
36
|
+
span.icon
|
|
37
|
+
i.fas.fa-sync-alt
|
|
38
|
+
span Refresh
|
|
39
|
+
|
|
40
|
+
#status-details
|
|
41
|
+
- if status[:details]
|
|
42
|
+
.content.is-small.mt-3
|
|
43
|
+
- if status[:status] == :error && status[:details][:issues]
|
|
44
|
+
strong Issues Found:
|
|
45
|
+
ul
|
|
46
|
+
- status[:details][:issues].each do |issue|
|
|
47
|
+
li #{issue}
|
|
48
|
+
- else
|
|
49
|
+
.columns.is-mobile
|
|
50
|
+
.column
|
|
51
|
+
.has-text-centered
|
|
52
|
+
.heading Scheme Assignments
|
|
53
|
+
.title.is-4 #{status[:details][:scheme_assignments] || 0}
|
|
54
|
+
.column
|
|
55
|
+
.has-text-centered
|
|
56
|
+
.heading Credential Assignments
|
|
57
|
+
.title.is-4 #{status[:details][:credential_assignments] || 0}
|
|
58
|
+
.column
|
|
59
|
+
.has-text-centered
|
|
60
|
+
.heading URL Mappings
|
|
61
|
+
.title.is-4 #{status[:details][:url_mappings] || 0}
|
|
62
|
+
- if status[:details][:global_mappings]
|
|
63
|
+
.column
|
|
64
|
+
.has-text-centered
|
|
65
|
+
.heading Global Mappings
|
|
66
|
+
.title.is-4 #{status[:details][:global_mappings]}
|
|
67
|
+
|
|
68
|
+
.columns
|
|
69
|
+
/ Left Column - Authentication Assignments
|
|
70
|
+
.column.is-half
|
|
71
|
+
/ Scheme Assignments Card
|
|
72
|
+
.card.mb-5
|
|
73
|
+
.card-header
|
|
74
|
+
.card-header-title
|
|
75
|
+
span.icon.mr-2
|
|
76
|
+
i.fas.fa-cogs
|
|
77
|
+
| Scheme Assignments
|
|
78
|
+
.card-header-icon
|
|
79
|
+
button.button.is-small.is-primary id="add-scheme-btn"
|
|
80
|
+
span.icon
|
|
81
|
+
i.fas.fa-plus
|
|
82
|
+
span Add Scheme
|
|
83
|
+
.card-content
|
|
84
|
+
#scheme-assignments
|
|
85
|
+
- if @agent_auth_data[:scheme_assignments].empty?
|
|
86
|
+
.has-text-grey-light.has-text-centered.py-4
|
|
87
|
+
span.icon.is-large
|
|
88
|
+
i.fas.fa-inbox.fa-2x
|
|
89
|
+
p.mt-2 No scheme assignments configured
|
|
90
|
+
p.is-size-7 Agent will use global authentication settings
|
|
91
|
+
- else
|
|
92
|
+
.table-container
|
|
93
|
+
table.table.is-fullwidth.is-striped
|
|
94
|
+
thead
|
|
95
|
+
tr
|
|
96
|
+
th Service
|
|
97
|
+
th Scheme
|
|
98
|
+
th Actions
|
|
99
|
+
tbody
|
|
100
|
+
- @agent_auth_data[:scheme_assignments].each do |service, scheme_name|
|
|
101
|
+
tr
|
|
102
|
+
td
|
|
103
|
+
span.tag.is-info #{service}
|
|
104
|
+
td
|
|
105
|
+
span.tag.is-primary #{scheme_name}
|
|
106
|
+
td
|
|
107
|
+
button.button.is-small.is-danger.is-outlined onclick="removeAssignment('scheme', '#{service}')"
|
|
108
|
+
span.icon
|
|
109
|
+
i.fas.fa-trash
|
|
110
|
+
span Remove
|
|
111
|
+
|
|
112
|
+
/ Credential Assignments Card
|
|
113
|
+
.card.mb-5
|
|
114
|
+
.card-header
|
|
115
|
+
.card-header-title
|
|
116
|
+
span.icon.mr-2
|
|
117
|
+
i.fas.fa-key
|
|
118
|
+
| Credential Assignments
|
|
119
|
+
.card-header-icon
|
|
120
|
+
button.button.is-small.is-primary id="add-credential-btn"
|
|
121
|
+
span.icon
|
|
122
|
+
i.fas.fa-plus
|
|
123
|
+
span Add Credential
|
|
124
|
+
.card-content
|
|
125
|
+
#credential-assignments
|
|
126
|
+
- if @agent_auth_data[:credential_assignments].empty?
|
|
127
|
+
.has-text-grey-light.has-text-centered.py-4
|
|
128
|
+
span.icon.is-large
|
|
129
|
+
i.fas.fa-inbox.fa-2x
|
|
130
|
+
p.mt-2 No credential assignments configured
|
|
131
|
+
p.is-size-7 Agent will use global authentication settings
|
|
132
|
+
- else
|
|
133
|
+
.table-container
|
|
134
|
+
table.table.is-fullwidth.is-striped
|
|
135
|
+
thead
|
|
136
|
+
tr
|
|
137
|
+
th Service
|
|
138
|
+
th Credential
|
|
139
|
+
th Actions
|
|
140
|
+
tbody
|
|
141
|
+
- @agent_auth_data[:credential_assignments].each do |service, credential_name|
|
|
142
|
+
tr
|
|
143
|
+
td
|
|
144
|
+
span.tag.is-info #{service}
|
|
145
|
+
td
|
|
146
|
+
span.tag.is-warning #{credential_name}
|
|
147
|
+
td
|
|
148
|
+
button.button.is-small.is-danger.is-outlined onclick="removeAssignment('credential', '#{service}')"
|
|
149
|
+
span.icon
|
|
150
|
+
i.fas.fa-trash
|
|
151
|
+
span Remove
|
|
152
|
+
|
|
153
|
+
/ Right Column - URL Mappings and Testing
|
|
154
|
+
.column.is-half
|
|
155
|
+
/ URL Mappings Card
|
|
156
|
+
.card.mb-5
|
|
157
|
+
.card-header
|
|
158
|
+
.card-header-title
|
|
159
|
+
span.icon.mr-2
|
|
160
|
+
i.fas.fa-link
|
|
161
|
+
| URL Mappings
|
|
162
|
+
.card-header-icon
|
|
163
|
+
button.button.is-small.is-primary id="add-mapping-btn"
|
|
164
|
+
span.icon
|
|
165
|
+
i.fas.fa-plus
|
|
166
|
+
span Add Mapping
|
|
167
|
+
.card-content
|
|
168
|
+
#url-mappings
|
|
169
|
+
- if @agent_auth_data[:url_mappings].empty?
|
|
170
|
+
.has-text-grey-light.has-text-centered.py-4
|
|
171
|
+
span.icon.is-large
|
|
172
|
+
i.fas.fa-inbox.fa-2x
|
|
173
|
+
p.mt-2 No URL mappings configured
|
|
174
|
+
p.is-size-7 Agent will use global URL mappings
|
|
175
|
+
- else
|
|
176
|
+
- @agent_auth_data[:url_mappings].each_with_index do |mapping, index|
|
|
177
|
+
.box.is-small.mb-3
|
|
178
|
+
.level.is-mobile
|
|
179
|
+
.level-left
|
|
180
|
+
.level-item
|
|
181
|
+
.content.is-small
|
|
182
|
+
strong #{mapping['pattern'] || mapping[:pattern]}
|
|
183
|
+
br
|
|
184
|
+
span.tag.is-small.is-primary #{mapping['scheme_name'] || mapping[:scheme_name]}
|
|
185
|
+
span.tag.is-small.is-warning.ml-1 #{mapping['credential_name'] || mapping[:credential_name]}
|
|
186
|
+
.level-right
|
|
187
|
+
.level-item
|
|
188
|
+
button.button.is-small.is-danger.is-outlined onclick="removeUrlMapping(#{index})"
|
|
189
|
+
span.icon
|
|
190
|
+
i.fas.fa-trash
|
|
191
|
+
|
|
192
|
+
/ Testing Card
|
|
193
|
+
.card
|
|
194
|
+
.card-header
|
|
195
|
+
.card-header-title
|
|
196
|
+
span.icon.mr-2
|
|
197
|
+
i.fas.fa-vial
|
|
198
|
+
| Authentication Testing
|
|
199
|
+
.card-content
|
|
200
|
+
.field
|
|
201
|
+
label.label Test URL (Optional)
|
|
202
|
+
.control.has-icons-left
|
|
203
|
+
input.input#test-url type="text" placeholder="https://api.example.com/endpoint"
|
|
204
|
+
span.icon.is-small.is-left
|
|
205
|
+
i.fas.fa-link
|
|
206
|
+
p.help Enter a URL to test authentication resolution for this agent
|
|
207
|
+
|
|
208
|
+
.field
|
|
209
|
+
.control
|
|
210
|
+
button.button.is-primary.is-fullwidth id="test-auth-btn"
|
|
211
|
+
span.icon
|
|
212
|
+
i.fas.fa-play
|
|
213
|
+
span Test Authentication
|
|
214
|
+
|
|
215
|
+
#test-results.mt-4 style="display: none;"
|
|
216
|
+
|
|
217
|
+
/ Modals
|
|
218
|
+
/ Add Scheme Assignment Modal
|
|
219
|
+
.modal#add-scheme-modal
|
|
220
|
+
.modal-background
|
|
221
|
+
.modal-card
|
|
222
|
+
header.modal-card-head
|
|
223
|
+
p.modal-card-title Add Scheme Assignment
|
|
224
|
+
button.delete aria-label="close" onclick="closeModal('add-scheme-modal')"
|
|
225
|
+
section.modal-card-body
|
|
226
|
+
.field
|
|
227
|
+
label.label Service Name
|
|
228
|
+
.control
|
|
229
|
+
input.input#scheme-service type="text" placeholder="e.g., github, slack, openai"
|
|
230
|
+
p.help The service or domain this scheme applies to
|
|
231
|
+
|
|
232
|
+
.field
|
|
233
|
+
label.label Authentication Scheme
|
|
234
|
+
.control
|
|
235
|
+
.select.is-fullwidth
|
|
236
|
+
select#scheme-select
|
|
237
|
+
option value="" Select a scheme...
|
|
238
|
+
- @agent_auth_data[:available_schemes].each do |scheme|
|
|
239
|
+
option value="#{scheme[:name]}" #{scheme[:name]} (#{scheme[:type]})
|
|
240
|
+
footer.modal-card-foot
|
|
241
|
+
button.button.is-primary onclick="addSchemeAssignment()" Add Assignment
|
|
242
|
+
button.button onclick="closeModal('add-scheme-modal')" Cancel
|
|
243
|
+
|
|
244
|
+
/ Add Credential Assignment Modal
|
|
245
|
+
.modal#add-credential-modal
|
|
246
|
+
.modal-background
|
|
247
|
+
.modal-card
|
|
248
|
+
header.modal-card-head
|
|
249
|
+
p.modal-card-title Add Credential Assignment
|
|
250
|
+
button.delete aria-label="close" onclick="closeModal('add-credential-modal')"
|
|
251
|
+
section.modal-card-body
|
|
252
|
+
.field
|
|
253
|
+
label.label Service Name
|
|
254
|
+
.control
|
|
255
|
+
input.input#credential-service type="text" placeholder="e.g., github, slack, openai"
|
|
256
|
+
p.help The service or domain this credential applies to
|
|
257
|
+
|
|
258
|
+
.field
|
|
259
|
+
label.label Authentication Credential
|
|
260
|
+
.control
|
|
261
|
+
.select.is-fullwidth
|
|
262
|
+
select#credential-select
|
|
263
|
+
option value="" Select a credential...
|
|
264
|
+
- @agent_auth_data[:available_credentials].each do |credential|
|
|
265
|
+
option value="#{credential[:name]}" #{credential[:name]} (#{credential[:type]})
|
|
266
|
+
footer.modal-card-foot
|
|
267
|
+
button.button.is-primary onclick="addCredentialAssignment()" Add Assignment
|
|
268
|
+
button.button onclick="closeModal('add-credential-modal')" Cancel
|
|
269
|
+
|
|
270
|
+
/ Add URL Mapping Modal
|
|
271
|
+
.modal#add-mapping-modal
|
|
272
|
+
.modal-background
|
|
273
|
+
.modal-card
|
|
274
|
+
header.modal-card-head
|
|
275
|
+
p.modal-card-title Add URL Mapping
|
|
276
|
+
button.delete aria-label="close" onclick="closeModal('add-mapping-modal')"
|
|
277
|
+
section.modal-card-body
|
|
278
|
+
.field
|
|
279
|
+
label.label URL Pattern
|
|
280
|
+
.control
|
|
281
|
+
input.input#mapping-pattern type="text" placeholder="https://api.github.com/*"
|
|
282
|
+
p.help Use * for wildcards or enter exact URLs
|
|
283
|
+
|
|
284
|
+
.field
|
|
285
|
+
label.label Pattern Type
|
|
286
|
+
.control
|
|
287
|
+
.select.is-fullwidth
|
|
288
|
+
select#pattern-type
|
|
289
|
+
option value="wildcard" selected Wildcard
|
|
290
|
+
option value="exact" Exact Match
|
|
291
|
+
option value="regex" Regular Expression
|
|
292
|
+
|
|
293
|
+
.field
|
|
294
|
+
label.label Authentication Scheme
|
|
295
|
+
.control
|
|
296
|
+
.select.is-fullwidth
|
|
297
|
+
select#mapping-scheme
|
|
298
|
+
option value="" Select a scheme...
|
|
299
|
+
- @agent_auth_data[:available_schemes].each do |scheme|
|
|
300
|
+
option value="#{scheme[:name]}" #{scheme[:name]} (#{scheme[:type]})
|
|
301
|
+
|
|
302
|
+
.field
|
|
303
|
+
label.label Authentication Credential
|
|
304
|
+
.control
|
|
305
|
+
.select.is-fullwidth
|
|
306
|
+
select#mapping-credential
|
|
307
|
+
option value="" Select a credential...
|
|
308
|
+
- @agent_auth_data[:available_credentials].each do |credential|
|
|
309
|
+
option value="#{credential[:name]}" #{credential[:name]} (#{credential[:type]})
|
|
310
|
+
|
|
311
|
+
.field
|
|
312
|
+
label.label Priority
|
|
313
|
+
.control
|
|
314
|
+
input.input#mapping-priority type="number" value="1" min="1" max="100"
|
|
315
|
+
p.help Higher numbers = higher priority (1-100)
|
|
316
|
+
footer.modal-card-foot
|
|
317
|
+
button.button.is-primary onclick="addUrlMapping()" Add Mapping
|
|
318
|
+
button.button onclick="closeModal('add-mapping-modal')" Cancel
|
|
319
|
+
|
|
320
|
+
javascript:
|
|
321
|
+
const agentName = '#{@agent_auth_data[:name]}';
|
|
322
|
+
|
|
323
|
+
// Modal management
|
|
324
|
+
function openModal(modalId) {
|
|
325
|
+
document.getElementById(modalId).classList.add('is-active');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function closeModal(modalId) {
|
|
329
|
+
document.getElementById(modalId).classList.remove('is-active');
|
|
330
|
+
// Clear form fields
|
|
331
|
+
const modal = document.getElementById(modalId);
|
|
332
|
+
const inputs = modal.querySelectorAll('input, select');
|
|
333
|
+
inputs.forEach(input => {
|
|
334
|
+
if (input.type === 'number') {
|
|
335
|
+
input.value = input.defaultValue || '1';
|
|
336
|
+
} else {
|
|
337
|
+
input.value = '';
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Event listeners for modal buttons
|
|
343
|
+
document.getElementById('add-scheme-btn').addEventListener('click', () => openModal('add-scheme-modal'));
|
|
344
|
+
document.getElementById('add-credential-btn').addEventListener('click', () => openModal('add-credential-modal'));
|
|
345
|
+
document.getElementById('add-mapping-btn').addEventListener('click', () => openModal('add-mapping-modal'));
|
|
346
|
+
|
|
347
|
+
// Add scheme assignment
|
|
348
|
+
function addSchemeAssignment() {
|
|
349
|
+
const service = document.getElementById('scheme-service').value.trim();
|
|
350
|
+
const schemeName = document.getElementById('scheme-select').value;
|
|
351
|
+
|
|
352
|
+
if (!service || !schemeName) {
|
|
353
|
+
alert('Please fill in all fields');
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
fetch(`/agents/${agentName}/auth/assign`, {
|
|
358
|
+
method: 'POST',
|
|
359
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
360
|
+
body: new URLSearchParams({
|
|
361
|
+
assignment_type: 'scheme',
|
|
362
|
+
service: service,
|
|
363
|
+
auth_name: schemeName
|
|
364
|
+
})
|
|
365
|
+
})
|
|
366
|
+
.then(response => response.json())
|
|
367
|
+
.then(data => {
|
|
368
|
+
if (data.success) {
|
|
369
|
+
closeModal('add-scheme-modal');
|
|
370
|
+
location.reload(); // Refresh to show updated assignments
|
|
371
|
+
} else {
|
|
372
|
+
alert('Error: ' + (data.error || 'Failed to add scheme assignment'));
|
|
373
|
+
}
|
|
374
|
+
})
|
|
375
|
+
.catch(error => {
|
|
376
|
+
console.error('Error:', error);
|
|
377
|
+
alert('Error adding scheme assignment');
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Add credential assignment
|
|
382
|
+
function addCredentialAssignment() {
|
|
383
|
+
const service = document.getElementById('credential-service').value.trim();
|
|
384
|
+
const credentialName = document.getElementById('credential-select').value;
|
|
385
|
+
|
|
386
|
+
if (!service || !credentialName) {
|
|
387
|
+
alert('Please fill in all fields');
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
fetch(`/agents/${agentName}/auth/assign`, {
|
|
392
|
+
method: 'POST',
|
|
393
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
394
|
+
body: new URLSearchParams({
|
|
395
|
+
assignment_type: 'credential',
|
|
396
|
+
service: service,
|
|
397
|
+
auth_name: credentialName
|
|
398
|
+
})
|
|
399
|
+
})
|
|
400
|
+
.then(response => response.json())
|
|
401
|
+
.then(data => {
|
|
402
|
+
if (data.success) {
|
|
403
|
+
closeModal('add-credential-modal');
|
|
404
|
+
location.reload(); // Refresh to show updated assignments
|
|
405
|
+
} else {
|
|
406
|
+
alert('Error: ' + (data.error || 'Failed to add credential assignment'));
|
|
407
|
+
}
|
|
408
|
+
})
|
|
409
|
+
.catch(error => {
|
|
410
|
+
console.error('Error:', error);
|
|
411
|
+
alert('Error adding credential assignment');
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Remove assignment
|
|
416
|
+
function removeAssignment(type, service) {
|
|
417
|
+
if (!confirm(`Remove ${type} assignment for service '${service}'?`)) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
fetch(`/agents/${agentName}/auth/remove`, {
|
|
422
|
+
method: 'DELETE',
|
|
423
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
424
|
+
body: new URLSearchParams({
|
|
425
|
+
assignment_type: type,
|
|
426
|
+
service: service
|
|
427
|
+
})
|
|
428
|
+
})
|
|
429
|
+
.then(response => response.json())
|
|
430
|
+
.then(data => {
|
|
431
|
+
if (data.success) {
|
|
432
|
+
location.reload(); // Refresh to show updated assignments
|
|
433
|
+
} else {
|
|
434
|
+
alert('Error: ' + (data.error || 'Failed to remove assignment'));
|
|
435
|
+
}
|
|
436
|
+
})
|
|
437
|
+
.catch(error => {
|
|
438
|
+
console.error('Error:', error);
|
|
439
|
+
alert('Error removing assignment');
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Add URL mapping
|
|
444
|
+
function addUrlMapping() {
|
|
445
|
+
const pattern = document.getElementById('mapping-pattern').value.trim();
|
|
446
|
+
const patternType = document.getElementById('pattern-type').value;
|
|
447
|
+
const schemeName = document.getElementById('mapping-scheme').value;
|
|
448
|
+
const credentialName = document.getElementById('mapping-credential').value;
|
|
449
|
+
const priority = document.getElementById('mapping-priority').value;
|
|
450
|
+
|
|
451
|
+
if (!pattern || !schemeName || !credentialName) {
|
|
452
|
+
alert('Please fill in all required fields');
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
fetch(`/agents/${agentName}/auth/url-mapping`, {
|
|
457
|
+
method: 'POST',
|
|
458
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
459
|
+
body: new URLSearchParams({
|
|
460
|
+
pattern: pattern,
|
|
461
|
+
pattern_type: patternType,
|
|
462
|
+
scheme_name: schemeName,
|
|
463
|
+
credential_name: credentialName,
|
|
464
|
+
priority: priority
|
|
465
|
+
})
|
|
466
|
+
})
|
|
467
|
+
.then(response => response.json())
|
|
468
|
+
.then(data => {
|
|
469
|
+
if (data.success) {
|
|
470
|
+
closeModal('add-mapping-modal');
|
|
471
|
+
location.reload(); // Refresh to show updated mappings
|
|
472
|
+
} else {
|
|
473
|
+
alert('Error: ' + (data.error || 'Failed to add URL mapping'));
|
|
474
|
+
}
|
|
475
|
+
})
|
|
476
|
+
.catch(error => {
|
|
477
|
+
console.error('Error:', error);
|
|
478
|
+
alert('Error adding URL mapping');
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Remove URL mapping
|
|
483
|
+
function removeUrlMapping(mappingId) {
|
|
484
|
+
if (!confirm('Remove this URL mapping?')) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
fetch(`/agents/${agentName}/auth/url-mapping/${mappingId}`, {
|
|
489
|
+
method: 'DELETE'
|
|
490
|
+
})
|
|
491
|
+
.then(response => response.json())
|
|
492
|
+
.then(data => {
|
|
493
|
+
if (data.success) {
|
|
494
|
+
location.reload(); // Refresh to show updated mappings
|
|
495
|
+
} else {
|
|
496
|
+
alert('Error: ' + (data.error || 'Failed to remove URL mapping'));
|
|
497
|
+
}
|
|
498
|
+
})
|
|
499
|
+
.catch(error => {
|
|
500
|
+
console.error('Error:', error);
|
|
501
|
+
alert('Error removing URL mapping');
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Test authentication
|
|
506
|
+
document.getElementById('test-auth-btn').addEventListener('click', function() {
|
|
507
|
+
const testUrl = document.getElementById('test-url').value.trim();
|
|
508
|
+
const resultsDiv = document.getElementById('test-results');
|
|
509
|
+
|
|
510
|
+
// Show loading state
|
|
511
|
+
this.classList.add('is-loading');
|
|
512
|
+
resultsDiv.style.display = 'block';
|
|
513
|
+
resultsDiv.innerHTML = '<div class="notification is-info">Running authentication tests...</div>';
|
|
514
|
+
|
|
515
|
+
const params = new URLSearchParams();
|
|
516
|
+
if (testUrl) {
|
|
517
|
+
params.append('test_url', testUrl);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
Legate.apiRequest(`/agents/${agentName}/auth/test`, {
|
|
521
|
+
method: 'POST',
|
|
522
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
523
|
+
body: params
|
|
524
|
+
})
|
|
525
|
+
.then(data => {
|
|
526
|
+
this.classList.remove('is-loading');
|
|
527
|
+
|
|
528
|
+
if (data.success !== undefined) {
|
|
529
|
+
let html = `<div class="notification is-${data.success ? 'success' : 'danger'}">`;
|
|
530
|
+
html += `<strong>Test Results for Agent: ${escapeHtml(data.agent_name)}</strong><br>`;
|
|
531
|
+
html += `Overall Status: ${data.success ? 'PASSED' : 'FAILED'}<br>`;
|
|
532
|
+
html += `Agent-specific Authentication: ${data.has_agent_auth ? 'Yes' : 'No (using global defaults)'}`;
|
|
533
|
+
html += '</div>';
|
|
534
|
+
|
|
535
|
+
if (data.tests && data.tests.length > 0) {
|
|
536
|
+
html += '<div class="content"><strong>Test Details:</strong><ul>';
|
|
537
|
+
data.tests.forEach(test => {
|
|
538
|
+
const statusClass = test.status === 'passed' ? 'has-text-success' :
|
|
539
|
+
test.status === 'warning' ? 'has-text-warning' : 'has-text-danger';
|
|
540
|
+
html += `<li class="${statusClass}"><strong>${escapeHtml(test.name)}:</strong> ${escapeHtml(test.message)}</li>`;
|
|
541
|
+
});
|
|
542
|
+
html += '</ul></div>';
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
resultsDiv.innerHTML = html;
|
|
546
|
+
} else {
|
|
547
|
+
Legate.renderError(resultsDiv, data.error);
|
|
548
|
+
}
|
|
549
|
+
})
|
|
550
|
+
.catch(error => {
|
|
551
|
+
this.classList.remove('is-loading');
|
|
552
|
+
console.error('Error:', error);
|
|
553
|
+
resultsDiv.innerHTML = '<div class="notification is-danger">Error running authentication tests</div>';
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
// Close modals when clicking background
|
|
558
|
+
document.querySelectorAll('.modal-background').forEach(bg => {
|
|
559
|
+
bg.addEventListener('click', function() {
|
|
560
|
+
this.closest('.modal').classList.remove('is-active');
|
|
561
|
+
});
|
|
562
|
+
});
|