diff --git a/app/javascript/controllers/clipboard_controller.js b/app/javascript/controllers/clipboard_controller.js index 7e0b1a493d1..b2f9d89472d 100644 --- a/app/javascript/controllers/clipboard_controller.js +++ b/app/javascript/controllers/clipboard_controller.js @@ -18,11 +18,21 @@ export default class extends Controller { } showSuccess() { + if (!this.hasIconDefaultTarget || !this.hasIconSuccessTarget) return; + this.iconDefaultTarget.classList.add("hidden"); this.iconSuccessTarget.classList.remove("hidden"); - setTimeout(() => { + + clearTimeout(this.resetTimeout); + this.resetTimeout = setTimeout(() => { this.iconDefaultTarget.classList.remove("hidden"); this.iconSuccessTarget.classList.add("hidden"); + this.resetTimeout = null; }, 3000); } + + disconnect() { + clearTimeout(this.resetTimeout); + this.resetTimeout = null; + } } diff --git a/app/views/layouts/settings.html.erb b/app/views/layouts/settings.html.erb index 49614c2373a..f08fa76a094 100644 --- a/app/views/layouts/settings.html.erb +++ b/app/views/layouts/settings.html.erb @@ -6,9 +6,9 @@ -
-
-
+
+
+
<% if content_for?(:breadcrumbs) %> <%= yield :breadcrumbs %> @@ -16,7 +16,7 @@ <%= render "layouts/shared/breadcrumbs", breadcrumbs: @breadcrumbs %> <% end %> -
+
<% if content_for?(:page_title) %>

<%= content_for :page_title %> @@ -25,7 +25,7 @@
<% end %> <% if content_for?(:page_actions) %> -
+
<%= yield :page_actions %>
<% end %> diff --git a/app/views/settings/api_keys/created.html.erb b/app/views/settings/api_keys/created.html.erb index 05f7eceb020..b9b7ce09a6a 100644 --- a/app/views/settings/api_keys/created.html.erb +++ b/app/views/settings/api_keys/created.html.erb @@ -22,14 +22,17 @@

Copy and store this key securely. You'll need it to authenticate your API requests.

-
- <%= @api_key.plain_key %> - <%= render DS::Button.new( - text: "Copy API Key", - variant: "ghost", - icon: "copy", - data: { action: "clipboard#copy" } - ) %> +
+ <%= @api_key.plain_key %> +
+ <%= render DS::Button.new( + variant: :icon, + icon: "copy", + title: "Copy", + aria: { label: "Copy" }, + data: { action: "clipboard#copy" } + ) %> +
@@ -76,10 +79,19 @@
-

How to use your API key

+

<%= t("settings.api_keys.created.usage_instructions_title") %>

<%= t("settings.api_keys.show.current_api_key.usage_instructions", product_name: product_name) %>

-
- curl -H "X-Api-Key: <%= @api_key.plain_key %>" <%= request.base_url %>/api/v1/accounts +
+ curl -H "X-Api-Key: <%= @api_key.plain_key %>" <%= request.base_url %>/api/v1/accounts +
+ <%= render DS::Button.new( + text: "Copy", + variant: "ghost", + icon: "copy", + class: "shrink-0", + data: { action: "clipboard#copy" } + ) %> +
diff --git a/app/views/settings/api_keys/created.turbo_stream.erb b/app/views/settings/api_keys/created.turbo_stream.erb index 89dab090b29..cced8f0bd11 100644 --- a/app/views/settings/api_keys/created.turbo_stream.erb +++ b/app/views/settings/api_keys/created.turbo_stream.erb @@ -27,14 +27,17 @@

Copy and store this key securely. You'll need it to authenticate your API requests.

-
- <%= @api_key.plain_key %> - <%= render DS::Button.new( - text: "Copy API Key", - variant: "ghost", - icon: "copy", - data: { action: "clipboard#copy" } - ) %> +
+ <%= @api_key.plain_key %> +
+ <%= render DS::Button.new( + variant: :icon, + icon: "copy", + title: "Copy", + aria: { label: "Copy" }, + data: { action: "clipboard#copy" } + ) %> +
@@ -81,10 +84,19 @@
-

How to use your API key

+

<%= t("settings.api_keys.created.usage_instructions_title") %>

Include your API key in the X-Api-Key header when making requests:

-
- curl -H "X-Api-Key: <%= @api_key.plain_key %>" <%= request.base_url %>/api/v1/accounts +
+ curl -H "X-Api-Key: <%= @api_key.plain_key %>" <%= request.base_url %>/api/v1/accounts +
+ <%= render DS::Button.new( + text: "Copy", + variant: "ghost", + icon: "copy", + class: "shrink-0", + data: { action: "clipboard#copy" } + ) %> +
diff --git a/app/views/settings/api_keys/new.html.erb b/app/views/settings/api_keys/new.html.erb index 20e322981be..763a1d7912b 100644 --- a/app/views/settings/api_keys/new.html.erb +++ b/app/views/settings/api_keys/new.html.erb @@ -51,7 +51,7 @@ ) %> <%= render DS::Button.new( - text: "Save API Key", + text: t("settings.api_keys.new.save_key"), variant: "primary", type: "submit" ) %> diff --git a/app/views/settings/api_keys/show.html.erb b/app/views/settings/api_keys/show.html.erb index 5aefbe56045..aa514b4c565 100644 --- a/app/views/settings/api_keys/show.html.erb +++ b/app/views/settings/api_keys/show.html.erb @@ -23,14 +23,16 @@

Copy and store this key securely. You'll need it to authenticate your API requests.

-
- <%= @current_api_key.plain_key %> - <%= render DS::Button.new( - text: "Copy API Key", - variant: "ghost", - icon: "copy", - data: { action: "clipboard#copy" } - ) %> +
+ <%= @current_api_key.plain_key %> +
+ <%= render DS::Button.new( + variant: "ghost", + icon: "copy", + class: "shrink-0", + data: { action: "clipboard#copy" } + ) %> +
@@ -38,8 +40,17 @@

How to use your API key

<%= t(".current_api_key.usage_instructions", product_name: product_name) %>

-
- curl -H "X-Api-Key: <%= @current_api_key.plain_key %>" <%= request.base_url %>/api/v1/accounts +
+ curl -H "X-Api-Key: <%= @current_api_key.plain_key %>" <%= request.base_url %>/api/v1/accounts +
+ <%= render DS::Button.new( + variant: :icon, + icon: "copy", + title: "Copy", + aria: { label: "Copy" }, + data: { action: "clipboard#copy" } + ) %> +
@@ -111,29 +122,41 @@

Copy and store this key securely. You'll need it to authenticate your API requests.

-
- <%= @current_api_key.plain_key %> - <%= render DS::Button.new( - text: "Copy API Key", - variant: "ghost", - icon: "copy", - data: { action: "clipboard#copy" } - ) %> +
+ <%= @current_api_key.plain_key %> +
+ <%= render DS::Button.new( + title: t(".current_api_key.copy_key"), + variant: "ghost", + icon: "copy", + class: "shrink-0", + data: { action: "clipboard#copy" } + ) %> +
-

How to use your API key

+

<%= t(".current_api_key.usage_instructions_title") %>

<%= t(".current_api_key.usage_instructions", product_name: product_name) %>

-
- curl -H "X-Api-Key: <%= @current_api_key.plain_key %>" <%= request.base_url %>/api/v1/accounts +
+ curl -H "X-Api-Key: <%= @current_api_key.plain_key %>" <%= request.base_url %>/api/v1/accounts +
+ <%= render DS::Button.new( + variant: :icon, + icon: "copy", + title: "Copy", + aria: { label: "Copy" }, + data: { action: "clipboard#copy" } + ) %> +
<%= render DS::Button.new( - text: "Revoke Key", + text: t("settings.api_keys.show.current_api_key.revoke_key"), href: settings_api_key_path, method: :delete, variant: "destructive", @@ -148,7 +171,7 @@ <%= content_for :page_title, t(".no_api_key.title") %> <%= content_for :page_actions do %> <%= render DS::Link.new( - text: t(".no_api_key.create_api_key"), + text: t("settings.api_keys.show.no_api_key.create_api_key"), href: new_settings_api_key_path, variant: "primary" ) %> diff --git a/config/locales/views/settings/api_keys/en.yml b/config/locales/views/settings/api_keys/en.yml index f6f3d4d4684..c6e96c04ce0 100644 --- a/config/locales/views/settings/api_keys/en.yml +++ b/config/locales/views/settings/api_keys/en.yml @@ -39,7 +39,7 @@ en: usage_instructions_title: "How to use your API key" usage_instructions: "Include your API key in the X-Api-Key header when making requests to the %{product_name} API:" regenerate_key: "Create New Key" - revoke_key: "Revoke Key" + revoke_key: "Revoke API Key" revoke_confirmation: "Are you sure you want to revoke this API key? This action cannot be undone and will immediately disable all applications using this key." new: title: "Create API Key" @@ -58,6 +58,7 @@ en: security_warning_title: "Important Security Notice" security_warning: "Your API key will be shown only once after creation. Store it securely and never share it publicly. If you lose it, you'll need to create a new one." create_key: "Create API Key" + save_key: "Save API Key" cancel: "Cancel" created: title: "API Key Created" diff --git a/test/system/settings/api_keys_test.rb b/test/system/settings/api_keys_test.rb index e558cb945ce..3664f606dd8 100644 --- a/test/system/settings/api_keys_test.rb +++ b/test/system/settings/api_keys_test.rb @@ -65,7 +65,7 @@ class Settings::ApiKeysTest < ApplicationSystemTestCase assert_text "Read/Write" assert_text "Never used" assert_link "Create New Key" - assert_button "Revoke Key" + assert_button "Revoke API Key" end test "should show usage instructions and example curl command" do @@ -121,7 +121,7 @@ class Settings::ApiKeysTest < ApplicationSystemTestCase visit settings_api_key_path # Click the revoke button to open the modal - click_button "Revoke Key" + click_button "Revoke API Key" # Wait for the dialog and then confirm assert_selector "#confirm-dialog", visible: true